private static async Task <ICommandResult> StartCommandOrchestration(IDurableClient durableClient, IOrchestratorCommand orchestratorCommand) { var orchestratorCommandMessage = new OrchestratorCommandMessage(orchestratorCommand); var orchestratorCommandResult = orchestratorCommand.CreateResult(); var orchestratorCommandOrchestration = orchestratorCommand switch { _ => $"{orchestratorCommand.GetType().Name}Orchestration" }; try { var instanceId = await durableClient .StartNewAsync <object>(orchestratorCommandOrchestration, orchestratorCommand.CommandId.ToString(), orchestratorCommandMessage) .ConfigureAwait(false); var status = await durableClient .GetStatusAsync(instanceId) .ConfigureAwait(false); orchestratorCommandResult.ApplyStatus(status); } catch (FunctionFailedException exc) { orchestratorCommandResult.Errors.Add(exc); } return(orchestratorCommandResult); } }
public async Task <ICommandResult> InvokeAsync(IOrchestratorCommand command) { if (command is null) { throw new ArgumentNullException(nameof(command)); } var commandResult = command.CreateResult(); try { var commandResponse = await options.Url .AppendPathSegment("api/command") .WithHeader("x-functions-key", options.AuthCode) .PostJsonAsync(command) .ConfigureAwait(false); commandResult = await commandResponse.Content .ReadAsAsync <ICommandResult>() .ConfigureAwait(false); commandResult.SetResultLinks(httpContextAccessor, commandResponse, command.ProjectId); } catch (FlurlHttpTimeoutException timeoutExc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(timeoutExc); } catch (FlurlHttpException serviceUnavailableExc) when(serviceUnavailableExc.Call.HttpStatus == HttpStatusCode.ServiceUnavailable) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(serviceUnavailableExc); } return(commandResult); }
private async Task <IActionResult> HandlePostAsync(IDurableClient durableClient, IAsyncCollector <string> commandMonitor, HttpRequestMessage requestMessage, ILogger log) { IOrchestratorCommand command = null; try { command = await requestMessage.Content .ReadAsJsonAsync <IOrchestratorCommand>() .ConfigureAwait(false); if (command is null) { return(new BadRequestResult()); } command.Validate(throwOnValidationError: true); } catch (ValidationException exc) { log.LogError(exc, $"Command {command?.CommandId} failed validation"); return(new BadRequestResult()); } if (TryGetOrchestratorCommandHandler(command, out var commandHandler)) { ICommandResult commandResult = null; try { await commandAuditWriter .AuditAsync(command) .ConfigureAwait(false); commandResult = await commandHandler .HandleAsync(command, durableClient) .ConfigureAwait(false); commandResult ??= await durableClient .GetCommandResultAsync(command) .ConfigureAwait(false); if (commandResult is null) { throw new NullReferenceException($"Unable to resolve result information for command {command.CommandId}"); } } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); // there are some edge cases that affect our action result // by returning specific result objects / status codes: switch (exc) { case NotImplementedException notImplementedException: // indicator something in the command's payload can't be processed return(new BadRequestResult()); case NotSupportedException notSupportedException: // indicator for a duplicate command return(new System.Web.Http.ConflictResult()); } } finally { if (commandResult.RuntimeStatus.IsFinal()) { await commandAuditWriter .AuditAsync(command, commandResult) .ConfigureAwait(false); } else { await commandMonitor .AddAsync(command.CommandId.ToString()) .ConfigureAwait(false); } } return(CreateCommandResultResponse(commandResult)); } else { return(new BadRequestResult()); } bool TryGetOrchestratorCommandHandler(IOrchestratorCommand orchestratorCommand, out IOrchestratorCommandHandler orchestratorCommandHandler) { using var scope = httpContextAccessor.HttpContext.RequestServices.CreateScope(); orchestratorCommandHandler = scope.ServiceProvider .GetServices <IOrchestratorCommandHandler>() .SingleOrDefault(handler => handler.CanHandle(orchestratorCommand)); return(!(orchestratorCommandHandler is null)); } }