示例#1
0
        public void ReleaseLocks()
        {
            if (this.ContextLocks != null)
            {
                foreach (var entityId in this.ContextLocks)
                {
                    var instance = new OrchestrationInstance()
                    {
                        InstanceId = EntityId.GetSchedulerIdFromEntityId(entityId)
                    };
                    var message = new ReleaseMessage()
                    {
                        ParentInstanceId = this.InstanceId,
                        LockRequestId    = this.LockRequestId,
                    };
                    this.SendEntityMessage(instance, "release", message);
                }

                this.ContextLocks  = null;
                this.lockReleaser  = null;
                this.LockRequestId = null;
            }
        }
        /// <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);
        }