private static async Task <ICommandResult> SwitchCommandAsync(IDurableOrchestrationContext functionContext, ProviderDocument provider, IProviderCommand command, ICommandResult commandResult, ILogger log) { try { await functionContext .AuditAsync(command, commandResult, provider) .ConfigureAwait(true); functionContext.SetCustomStatus($"Switching command", log); var project = await functionContext .GetProjectAsync(command.ProjectId, allowUnsafe : true) .ConfigureAwait(true); functionContext.ContinueAsNew(( new ProviderProjectUpdateCommand ( command.BaseApi, command.User as Model.Data.User, project.PopulateExternalModel(), command.CommandId), provider ) ); } catch (Exception exc) { functionContext.SetCustomStatus($"Switching command failed: {exc.Message}", log, exc); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } return(commandResult); }
private static async Task <ICommandResult> ProcessCommandAsync(IDurableOrchestrationContext functionContext, ProviderDocument provider, IProviderCommand command, ICommandResult commandResult, ILogger log) { var commandMessage = default(ICommandMessage); var commandCallback = default(string); try { functionContext.SetCustomStatus($"Acquire callback url", log); commandCallback = await functionContext .CallActivityWithRetryAsync <string>(nameof(CallbackUrlGetActivity), (functionContext.InstanceId, command)) .ConfigureAwait(true); commandMessage = new ProviderCommandMessage(command, commandCallback); if (!(command is ProviderRegisterCommand || provider.Registered.HasValue)) { log.LogInformation($"Register provider {provider.Id} for command {command.CommandId}"); await functionContext .RegisterProviderAsync(provider, true) .ConfigureAwait(true); } if (!string.IsNullOrEmpty(command.ProjectId) && provider.PrincipalId.HasValue) { log.LogInformation($"Enable provider {provider.Id} for command {command.CommandId}"); await functionContext .CallActivityWithRetryAsync(nameof(ProjectResourcesAccessActivity), (command.ProjectId, provider.PrincipalId.Value)) .ConfigureAwait(true); } functionContext.SetCustomStatus($"Augmenting command", log); command = await AugmentCommandAsync(functionContext, provider, command) .ConfigureAwait(true); await functionContext .AuditAsync(command, commandResult, provider) .ConfigureAwait(true); try { functionContext.SetCustomStatus($"Sending command", log); commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandSendActivity), (provider, commandMessage)) .ConfigureAwait(true); } catch (RetryCanceledException) { commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultFetchActivity), (provider, commandMessage)) .ConfigureAwait(true); } finally { await functionContext .AuditAsync(command, commandResult, provider) .ConfigureAwait(true); } if (commandResult.RuntimeStatus.IsActive()) { var commandTimeout = (commandResult.Timeout > TimeSpan.Zero && commandResult.Timeout < CommandResult.MaximumTimeout) ? commandResult.Timeout // use the timeout reported back by the provider : CommandResult.MaximumTimeout; // use the defined maximum timeout functionContext.SetCustomStatus($"Waiting for command result", log); commandResult = await functionContext .WaitForExternalEvent <ICommandResult>(command.CommandId.ToString(), commandTimeout, null) .ConfigureAwait(true); if (commandResult is null) { // provider ran into a timeout // lets give our provider a last // chance to return a command result commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultFetchActivity), (provider, commandMessage)) .ConfigureAwait(true); if (commandResult.RuntimeStatus.IsActive()) { // the last change result still doesn't report a final runtime status // escalate the timeout by throwing an appropriate exception throw new TimeoutException($"Provider '{provider.Id}' ran into timeout ({commandTimeout})"); } } } } catch (Exception exc) { functionContext.SetCustomStatus($"Sending command failed: {exc.Message}", log, exc); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc.AsSerializable()); } finally { await functionContext .AuditAsync(command, commandResult, provider) .ConfigureAwait(true); await ProcessOutputAsync(functionContext, provider, command, commandResult) .ConfigureAwait(true); } return(commandResult); }