/// <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); }