示例#1
0
        public bool CanHandle(IOrchestratorCommand orchestratorCommand)
        {
            if (orchestratorCommand is null)
            {
                throw new ArgumentNullException(nameof(orchestratorCommand));
            }

            var orchestrationName = GetCommandOrchestrationName(orchestratorCommand);

            return(FunctionsEnvironment.FunctionExists(orchestrationName));
        }
示例#2
0
        public async Task <ICommandResult> HandleAsync(IOrchestratorCommand orchestratorCommand, IDurableClient durableClient = null)
        {
            if (orchestratorCommand is null)
            {
                throw new ArgumentNullException(nameof(orchestratorCommand));
            }

            if (durableClient is null)
            {
                throw new ArgumentNullException(nameof(durableClient));
            }

            if (CanHandle(orchestratorCommand))
            {
                var wrapperInstanceId = GetCommandOrchestrationWrapperInstanceId(orchestratorCommand.CommandId);

                try
                {
                    _ = await durableClient
                        .StartNewAsync(nameof(OrchestratorCommandOrchestration), wrapperInstanceId, orchestratorCommand)
                        .ConfigureAwait(false);
                }
                catch (InvalidOperationException exc)
                {
                    if ((await durableClient.GetCommandResultAsync(orchestratorCommand).ConfigureAwait(false)) is null)
                    {
                        throw; // bubble exception - as we can't find a command wrapper orchestration.
                    }
                    else
                    {
                        throw new NotSupportedException($"Orchstration for command {orchestratorCommand.CommandId} can only started once", exc);
                    }
                }

                return(await durableClient
                       .GetCommandResultAsync(orchestratorCommand)
                       .ConfigureAwait(false));
            }

            throw new NotImplementedException($"Missing orchestration to handle {orchestratorCommand.GetType().Name} at {GetType()}");
        }
示例#3
0
        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);
        }
示例#4
0
        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));
            }
        }
示例#5
0
 public OrchestratorCommandException(string message, IOrchestratorCommand orchestratorCommand, Exception inner) : base(message, orchestratorCommand, inner)
 {
 }
示例#6
0
 public OrchestratorCommandException(string message, IOrchestratorCommand orchestratorCommand) : base(message, orchestratorCommand)
 {
 }
示例#7
0
        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);
        }
    }