/// <inheritdoc /> async Task <EntityQueryResult> IDurableEntityClient.ListEntitiesAsync(EntityQuery query, CancellationToken cancellationToken) { var condition = new OrchestrationStatusQueryCondition(query); var result = await((IDurableClient)this).ListInstancesAsync(condition, cancellationToken); var entityResult = new EntityQueryResult(result); return(entityResult); }
private async Task <HttpResponseMessage> HandleGetStatusRequestAsync( HttpRequestMessage request) { IDurableOrchestrationClient client = this.GetClient(request); var queryNameValuePairs = request.GetQueryNameValuePairs(); var condition = new OrchestrationStatusQueryCondition(); if (TryGetDateTimeQueryParameterValue(queryNameValuePairs, CreatedTimeFromParameter, out DateTime createdTimeFrom)) { condition.CreatedTimeFrom = createdTimeFrom; } if (TryGetDateTimeQueryParameterValue(queryNameValuePairs, CreatedTimeToParameter, out DateTime createdTimeTo)) { condition.CreatedTimeTo = createdTimeTo; } if (TryGetIEnumerableQueryParameterValue <OrchestrationRuntimeStatus>(queryNameValuePairs, RuntimeStatusParameter, out IEnumerable <OrchestrationRuntimeStatus> runtimeStatus)) { condition.RuntimeStatus = runtimeStatus; } if (TryGetBooleanQueryParameterValue(queryNameValuePairs, ShowInputParameter, out bool showInput)) { condition.ShowInput = showInput; } if (TryGetIntQueryParameterValue(queryNameValuePairs, PageSizeParameter, out int pageSize)) { condition.PageSize = pageSize; } if (request.Headers.TryGetValues("x-ms-continuation-token", out var headerValues)) { condition.ContinuationToken = headerValues.FirstOrDefault(); } IList <DurableOrchestrationStatus> statusForAllInstances; var context = await client.ListInstancesAsync(condition, CancellationToken.None); statusForAllInstances = context.DurableOrchestrationState.ToList(); var nextContinuationToken = context.ContinuationToken; var results = new List <StatusResponsePayload>(statusForAllInstances.Count); foreach (var state in statusForAllInstances) { results.Add(ConvertFrom(state)); } var response = request.CreateResponse(HttpStatusCode.OK, results); response.Headers.Add("x-ms-continuation-token", nextContinuationToken); return(response); }
private async Task <HttpResponseMessage> HandleGetStatusRequestAsync( HttpRequestMessage request) { IDurableOrchestrationClient client = this.GetClient(request); var queryNameValuePairs = request.GetQueryNameValuePairs(); var createdTimeFrom = GetDateTimeQueryParameterValue(queryNameValuePairs, CreatedTimeFromParameter, default(DateTime)); var createdTimeTo = GetDateTimeQueryParameterValue(queryNameValuePairs, CreatedTimeToParameter, default(DateTime)); var runtimeStatus = GetIEnumerableQueryParameterValue <OrchestrationRuntimeStatus>(queryNameValuePairs, RuntimeStatusParameter); var pageSize = GetIntQueryParameterValue(queryNameValuePairs, PageSizeParameter); var continuationToken = ""; if (request.Headers.TryGetValues("x-ms-continuation-token", out var headerValues)) { continuationToken = headerValues.FirstOrDefault(); } IList <DurableOrchestrationStatus> statusForAllInstances; var nextContinuationToken = ""; if (pageSize > 0) { var condition = new OrchestrationStatusQueryCondition() { CreatedTimeFrom = createdTimeFrom, CreatedTimeTo = createdTimeTo, RuntimeStatus = runtimeStatus, PageSize = pageSize, ContinuationToken = continuationToken, }; var context = await client.GetStatusAsync(condition, CancellationToken.None); statusForAllInstances = context.DurableOrchestrationState.ToList(); nextContinuationToken = context.ContinuationToken; } else { statusForAllInstances = await client.GetStatusAsync(createdTimeFrom, createdTimeTo, runtimeStatus); } var results = new List <StatusResponsePayload>(statusForAllInstances.Count); foreach (var state in statusForAllInstances) { results.Add(this.ConvertFrom(state)); } var response = request.CreateResponse(HttpStatusCode.OK, results); response.Headers.Add("x-ms-continuation-token", nextContinuationToken); return(response); }
private OrchestrationStatusQueryCondition CreateConditionFromParameters(DateTime?createdTimeFrom, DateTime?createdTimeTo, IEnumerable <OrchestrationRuntimeStatus> runtimeStatus) { var condition = new OrchestrationStatusQueryCondition(); if (createdTimeFrom != null) { condition.CreatedTimeFrom = createdTimeFrom.Value; } if (createdTimeTo != null) { condition.CreatedTimeTo = createdTimeTo.Value; } if (runtimeStatus != null) { condition.RuntimeStatus = runtimeStatus; } return(condition); }
internal static OrchestrationInstanceStatusQueryCondition ConvertWebjobsDurableConditionToAzureStorageCondition(OrchestrationStatusQueryCondition condition) { return(new OrchestrationInstanceStatusQueryCondition { RuntimeStatus = condition.RuntimeStatus?.Select( p => (OrchestrationStatus)Enum.Parse(typeof(OrchestrationStatus), p.ToString())), CreatedTimeFrom = condition.CreatedTimeFrom, CreatedTimeTo = condition.CreatedTimeTo, TaskHubNames = condition.TaskHubNames, InstanceIdPrefix = condition.InstanceIdPrefix, FetchInput = condition.ShowInput, }); }
/// <inheritdoc/> public async override Task <OrchestrationStatusQueryResult> GetOrchestrationStateWithPagination(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { var statusContext = await this.serviceClient.GetOrchestrationStateAsync(ConvertWebjobsDurableConditionToAzureStorageCondition(condition), condition.PageSize, condition.ContinuationToken, cancellationToken); return(this.ConvertFrom(statusContext)); }
/// <inheritdoc /> async Task <CleanEntityStorageResult> IDurableEntityClient.CleanEntityStorageAsync(bool removeEmptyEntities, bool releaseOrphanedLocks, CancellationToken cancellationToken) { DateTime now = DateTime.UtcNow; CleanEntityStorageResult finalResult = default; var condition = new OrchestrationStatusQueryCondition() { InstanceIdPrefix = "@", ShowInput = false, }; // list all entities (without fetching the input) and for each one that requires action, // perform that action. Waits for all actions to finish after each page. do { var page = await this.DurabilityProvider.GetOrchestrationStateWithPagination(condition, cancellationToken); List <Task> tasks = new List <Task>(); foreach (var state in page.DurableOrchestrationState) { EntityStatus status = this.messageDataConverter.Deserialize <EntityStatus>(state.CustomStatus.ToString()); if (releaseOrphanedLocks && status.LockedBy != null) { tasks.Add(CheckForOrphanedLockAndFixIt(state, status.LockedBy)); } if (removeEmptyEntities) { bool isEmptyEntity = !status.EntityExists && status.LockedBy == null && status.QueueSize == 0; bool safeToRemoveWithoutBreakingMessageSorterLogic = now - state.LastUpdatedTime > this.config.MessageReorderWindow; if (isEmptyEntity && safeToRemoveWithoutBreakingMessageSorterLogic) { tasks.Add(DeleteIdleOrchestrationEntity(state)); } } } async Task DeleteIdleOrchestrationEntity(DurableOrchestrationStatus status) { await this.DurabilityProvider.PurgeInstanceHistoryByInstanceId(status.InstanceId); Interlocked.Increment(ref finalResult.NumberOfEmptyEntitiesRemoved); } async Task CheckForOrphanedLockAndFixIt(DurableOrchestrationStatus status, string lockOwner) { var findRunningOwner = new OrchestrationStatusQueryCondition() { InstanceIdPrefix = lockOwner, ShowInput = false, RuntimeStatus = RunningStatus, }; var result = await this.DurabilityProvider.GetOrchestrationStateWithPagination(findRunningOwner, cancellationToken); if (!result.DurableOrchestrationState.Any(state => state.InstanceId == lockOwner)) { // the owner is not a running orchestration. Send a lock release. var message = new ReleaseMessage() { ParentInstanceId = lockOwner, LockRequestId = "fix-orphaned-lock", // we don't know the original id but it does not matter }; await this.RaiseEventInternalAsync(this.client, this.TaskHubName, status.InstanceId, EntityMessageEventNames.ReleaseMessageEventName, message); Interlocked.Increment(ref finalResult.NumberOfOrphanedLocksRemoved); } } await Task.WhenAll(tasks); condition.ContinuationToken = page.ContinuationToken; }while (condition.ContinuationToken != null); return(finalResult); }
/// <inheritdoc /> Task <OrchestrationStatusQueryResult> IDurableOrchestrationClient.ListInstancesAsync( OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { return(this.DurabilityProvider.GetOrchestrationStateWithPagination(condition, cancellationToken)); }
Task <OrchestrationStatusQueryResult> IDurableOrchestrationClient.GetStatusAsync( OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { return(((IDurableOrchestrationClient)this).ListInstancesAsync(condition, cancellationToken)); }
/// <summary> /// Gets paginated result of all orchestration instances that match query status parameters. /// </summary> /// <param name="condition">The filtering conditions of the query.</param> /// <param name="cancellationToken">A token to cancel the request.</param> /// <returns>Paginated result of orchestration state.</returns> public virtual Task <OrchestrationStatusQueryResult> GetOrchestrationStateWithPagination(OrchestrationStatusQueryCondition condition, CancellationToken cancellationToken) { throw this.GetNotImplementedException(nameof(this.GetOrchestrationStateWithPagination)); }