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 async Task <OrchestrationState> GetOrchestrationState(string orchestrationId)
        {
            IDatabase redisDatabase          = this.redisConnection.GetDatabase();
            string    orchestrationStateKey  = RedisKeyNameResolver.GetOrchestrationStateKey(this.taskHub, this.partition, orchestrationId);
            string    orchestrationStateJson = await redisDatabase.StringGetAsync(orchestrationStateKey);

            if (orchestrationStateJson == null)
            {
                return(null);
            }
            return(RedisSerializer.DeserializeObject <OrchestrationState>(orchestrationStateJson));
        }
        public RedisTransactionBuilder AddOrchestrationStateToHistory(string orchestrationId, OrchestrationState state)
        {
            if (this.partition == null)
            {
                throw new ArgumentNullException($"Cannot call {nameof(AddOrchestrationStateToHistory)} without a partition set.");
            }
            string orchestrationStateKey = RedisKeyNameResolver.GetOrchestrationStateKey(this.taskHub, this.partition, orchestrationId);
            string stateJson             = RedisSerializer.SerializeObject(state);

            // Add to front of list so history in latest to oldest order
            transaction.StringSetAsync(orchestrationStateKey, stateJson);
            return(this);
        }