/// <inheritdoc />
        public async Task CompleteTaskActivityWorkItemAsync(
            TaskActivityWorkItem workItem,
            TaskMessage responseMessage)
        {
            if (this.activityTaskManager == null || this.partitionOrchestrationManager == null)
            {
                await StartAsync();
            }
            RedisTransactionBuilder transactionBuilder = this.partitionOrchestrationManager.CreateExistingOrchestrationTransaction(responseMessage.OrchestrationInstance.InstanceId)
                                                         .SendControlQueueMessage(responseMessage)
                                                         .RemoveTaskMessageFromActivityQueue(workItem.TaskMessage, this.workerGuid);

            bool transactionSucceeded = await transactionBuilder.CommitTransactionAsync();

            string logMessage;

            if (transactionSucceeded)
            {
                logMessage = $"Succeeded in transaction of finishing task activity item: activity event id={workItem.TaskMessage.Event.EventId}, orchestration event id: {responseMessage.Event.EventId}";
            }
            else
            {
                logMessage = $"Failed in transaction of finishing task activity item: activity event id={workItem.TaskMessage.Event.EventId}, orchestration event id: {responseMessage.Event.EventId}";
            }
            await this.logger.LogAsync(logMessage);
        }
        public async Task CreateTaskOrchestration(TaskMessage creationMessage, OrchestrationStatus[] dedupeStatuses)
        {
            if (!(creationMessage.Event is ExecutionStartedEvent executionStartEvent))
            {
                throw new InvalidOperationException("Invalid creation task message");
            }
            string orchestrationId = creationMessage.OrchestrationInstance.InstanceId;

            // Lock so that two clients can't create the same orchestrationId at the same time.
            await this.orchestrationCurrentStateLock.WaitAsync();

            IDatabase redisDB = this.redisConnection.GetDatabase();
            string    orchestrationHistoryKey = RedisKeyNameResolver.GetOrchestrationStateKey(this.taskHub, this.partition, orchestrationId);
            string    currentStateJson        = await redisDB.StringGetAsync(orchestrationHistoryKey);

            if (currentStateJson != null)
            {
                OrchestrationState currentState = RedisSerializer.DeserializeObject <OrchestrationState>(currentStateJson);
                if (dedupeStatuses == null || dedupeStatuses.Contains(currentState.OrchestrationStatus))
                {
                    // An orchestration with same instance id is already running
                    throw new OrchestrationAlreadyExistsException($"An orchestration with id '{creationMessage.OrchestrationInstance.InstanceId}' already exists. It is in state {currentState.OrchestrationStatus}");
                }
            }

            RedisTransactionBuilder transactionBuilder = this.CreateNonExistingOrchestrationTransaction(orchestrationId);
            var state = new OrchestrationState
            {
                OrchestrationInstance = new OrchestrationInstance
                {
                    InstanceId  = creationMessage.OrchestrationInstance.InstanceId,
                    ExecutionId = creationMessage.OrchestrationInstance.ExecutionId,
                },
                CreatedTime         = DateTime.UtcNow,
                OrchestrationStatus = OrchestrationStatus.Pending,
                Version             = executionStartEvent.Version,
                Name  = executionStartEvent.Name,
                Input = executionStartEvent.Input,
            };

            transactionBuilder.AddOrchestrationToSet(orchestrationId);
            transactionBuilder.AddOrchestrationStateToHistory(orchestrationId, state);
            transactionBuilder.SendControlQueueMessage(creationMessage);
            bool transactionSucceeded = await transactionBuilder.CommitTransactionAsync();

            string logMessage;

            if (transactionSucceeded)
            {
                logMessage = "Succeeded in transaction of creating task orchestration";
            }
            else
            {
                logMessage = "Failed in transaction of creating task orchestration";
            }
            await this.logger.LogAsync(logMessage);

            this.orchestrationCurrentStateLock.Release();
        }
        public RedisTransactionBuilder CreateNonExistingOrchestrationTransaction(string orchestrationId)
        {
            IDatabase redisDatabase = this.redisConnection.GetDatabase();

            return(RedisTransactionBuilder.BuildTransactionInPartition(
                       taskHub: this.taskHub,
                       partition: this.partition,
                       connection: this.redisConnection,
                       condition: Condition.SetNotContains(this.currentOrchestrationsSetKey, orchestrationId)));
        }
        /// <inheritdoc />
        public async Task CompleteTaskOrchestrationWorkItemAsync(
            TaskOrchestrationWorkItem workItem,
            OrchestrationRuntimeState newOrchestrationRuntimeState,
            IList <TaskMessage> outboundMessages,
            IList <TaskMessage> orchestratorMessages,
            IList <TaskMessage> timerMessages,
            TaskMessage continuedAsNewMessage,
            OrchestrationState orchestrationState)
        {
            if (this.partitionOrchestrationManager == null || this.redisConnection == null)
            {
                await StartAsync();
            }
            string orchestrationId = workItem.InstanceId;
            RedisTransactionBuilder transaction = this.partitionOrchestrationManager.CreateExistingOrchestrationTransaction(orchestrationId);

            List <string> events = newOrchestrationRuntimeState.Events.Select(histEvent => histEvent as TaskCompletedEvent)
                                   .Where(taskCompletedEvent => taskCompletedEvent != null)
                                   .OrderBy(task => task.TaskScheduledId)
                                   .Select(TaskCompletedEvent => $"{{\"id\": {TaskCompletedEvent.TaskScheduledId}, \"Result\": {TaskCompletedEvent.Result}}}")
                                   .ToList();
            string logMessage = "Current events processed: " + string.Join(",", events);

            await this.logger.LogAsync(logMessage);

            transaction.SetOrchestrationRuntimeState(orchestrationId, newOrchestrationRuntimeState);

            foreach (TaskMessage outboundMessage in outboundMessages)
            {
                transaction.SendActivityMessage(outboundMessage);
            }

            foreach (TaskMessage message in orchestratorMessages)
            {
                transaction.SendControlQueueMessage(message);
            }

            if (continuedAsNewMessage != null)
            {
                transaction.SendControlQueueMessage(continuedAsNewMessage);
            }

            // TODO send timer messages in transaction

            transaction.AddOrchestrationStateToHistory(orchestrationId: orchestrationId,
                                                       state: orchestrationState);

            transaction.RemoveItemsFromOrchestrationQueue(orchestrationId, workItem.NewMessages.Count);

            bool transactionSucceeded = await transaction.CommitTransactionAsync();

            if (transactionSucceeded)
            {
                logMessage = $"Succeeded in transaction of finishing task orchestration item: execution id={workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId}, numMessagesProcessed: {workItem.NewMessages.Count}, numOutBoundMessages: {outboundMessages.Count}, numOrchMessages: {orchestratorMessages.Count}";
            }
            else
            {
                logMessage = $"Failed in transaction of finishing task orchestration item: execution id={workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId}, numMessagesProcessed: {workItem.NewMessages.Count}, numOutBoundMessages: {outboundMessages.Count}, numOrchMessages: {orchestratorMessages.Count}";
            }
            await this.logger.LogAsync(logMessage);
        }