/// <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));
 }
Beispiel #10
0
 /// <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));
 }