public async Task Orchestrator([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var activity = context.CreateActivityProxy <ISharedActivity>(); // 期限切れまで 30 日以内の証明書を取得する var certificates = await activity.GetExpiringCertificates(context.CurrentUtcDateTime); // 更新対象となる証明書がない場合は終わる if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } // 証明書の更新を行う foreach (var certificate in certificates) { var dnsNames = certificate.DnsNames; log.LogInformation($"{certificate.Id} - {certificate.ExpiresOn}"); try { // 証明書の更新処理を開始 await context.CallSubOrchestratorWithRetryAsync(nameof(SharedOrchestrator.IssueCertificate), _retryOptions, dnsNames); } catch (Exception ex) { // 失敗した場合はログに詳細を書き出して続きを実行する log.LogError($"Failed sub orchestration with DNS names = {string.Join(",", dnsNames)}"); log.LogError(ex.Message); } } }
public static async Task MainOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { OrchestrationConfiguration process = context.GetInput <OrchestrationConfiguration>(); //copy callback URL when demoing this foreach (OrchestrationStep step in process.steps) { var retryOptions = new RetryOptions( firstRetryInterval: TimeSpan.FromSeconds(5), maxNumberOfAttempts: (step.maxRetryCount > 0)? step.maxRetryCount + 1:1); try { step.timeOut = (step.timeOut == 0) ? process.defaultStepTimeOut : step.timeOut; var result = await context.CallSubOrchestratorWithRetryAsync <bool>( nameof(SingleStepOrchestration), retryOptions, step); } catch { if (!context.IsReplaying) { log.LogWarning("-------step {0} failed-----------------", step.stepName); if (step.stopFlowOnFailure) { break; } } } } log.LogInformation("------------------ORCHESTRATION IS OVER-----------------"); }
internal static async Task <TCommandResult> SendProviderCommandAsync <TCommand, TCommandResult>(this IDurableOrchestrationContext functionContext, TCommand command, ProviderDocument provider) where TCommand : IProviderCommand where TCommandResult : ICommandResult { if (command is null) { throw new ArgumentNullException(nameof(command)); } if (provider is null) { throw new ArgumentNullException(nameof(provider)); } command.ProviderId = provider.Id; var providerResult = (TCommandResult)await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(nameof(ProviderSendOrchestration), (command, provider)) .ConfigureAwait(true); if (providerResult is null) { providerResult = (TCommandResult)command.CreateResult(); providerResult.Errors.Add(new NullReferenceException($"Provider '{provider.Id}' returned no result for command '{command.CommandId}'")); } return(providerResult); }
public static async Task OrchestratorWithRetry_NullRetryOptions([OrchestrationTrigger] IDurableOrchestrationContext ctx) { string message = ctx.GetInput <string>(); RetryOptions options = null; // This throw happens in the implementation of an orchestrator. await ctx.CallSubOrchestratorWithRetryAsync(nameof(TestOrchestrations.ThrowOrchestrator), options, message); }
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var command = functionContext.GetInput <ProviderProjectUpdateCommand>(); var commandResult = command.CreateResult(); var commandLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); using (log.BeginCommandScope(command)) { try { await functionContext .EnsureAuthorizedAsync() .ConfigureAwait(true); await functionContext .CallActivityWithRetryAsync(nameof(ProjectUpdateActivity), command.Payload) .ConfigureAwait(true); await functionContext .CallSubOrchestratorWithRetryAsync(nameof(ProjectSyncOrchestration), command.Payload) .ConfigureAwait(true); commandResult.Result = new ProviderOutput { Properties = new Dictionary <string, string>() }; } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); throw exc.AsSerializable(); } finally { var commandException = commandResult.Errors?.ToException(); if (commandException is null) { functionContext.SetCustomStatus($"Command succeeded", commandLog); } else { functionContext.SetCustomStatus($"Command failed: {commandException.Message}", commandLog, commandException); } functionContext.SetOutput(commandResult); } } }
public async Task RunWithSubOrchestrators( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var name = context.GetInput <string>(); var function1Result = await context.CallActivityWithRetryAsync <Function1Result>( nameof(ActivityFunction1), GetDefaultRetryOptions(), name); var orchestratorAResult = await context.CallSubOrchestratorWithRetryAsync <DemoOrchestratorAResult>( nameof(DemoOrchestratorA), GetDefaultRetryOptions(), function1Result); await context.CallSubOrchestratorWithRetryAsync( nameof(DemoOrchestratorB), GetDefaultRetryOptions(), orchestratorAResult); }
public async Task <MyOrchestrationDto> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var myOrchestrationDto = new MyOrchestrationDto { InputStartData = context.GetInput <string>() }; if (!context.IsReplaying) { log.LogWarning($"begin MyOrchestration with input {context.GetInput<string>()}"); } var retryOptions = new RetryOptions( firstRetryInterval: TimeSpan.FromSeconds(3), maxNumberOfAttempts: 5) { BackoffCoefficient = 1.5 }; var myActivityOne = await context.CallActivityWithRetryAsync <string> (Constants.MyActivityOne, retryOptions, context.GetInput <string>()); myOrchestrationDto.MyActivityOneResult = myActivityOne; if (!context.IsReplaying) { log.LogWarning($"myActivityOne completed {myActivityOne}"); } var mySubOrchestrationDto = await context.CallSubOrchestratorWithRetryAsync <MySubOrchestrationDto> (Constants.MySecondOrchestration, retryOptions, myActivityOne); myOrchestrationDto.MySubOrchestration = mySubOrchestrationDto; if (!context.IsReplaying) { log.LogWarning($"mySubOrchestrationDto completed {mySubOrchestrationDto.MyActivityThreeResult}"); } var myActivityTwo = await context.CallActivityAsync <string>( Constants.MyActivityTwo, "Start MyOrchestration Activity 2"); myOrchestrationDto.MyActivityTwoResult = myActivityTwo; if (!context.IsReplaying) { log.LogWarning($"myActivityTwo completed {myActivityTwo}"); } return(myOrchestrationDto); }
internal static async Task InitializeSubscriptionAsync(this IDurableOrchestrationContext functionContext, Guid subscriptionId) { var currentSubscriptionVersion = await functionContext .GetSubscriptionVersionAsync(subscriptionId) .ConfigureAwait(true); if (currentSubscriptionVersion != TargetSubscriptionVersion) { await functionContext .CallSubOrchestratorWithRetryAsync(nameof(SubscriptionInitializationOrchestration), subscriptionId) .ConfigureAwait(true); } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var command = functionContext.GetInput <ICommand>(); var commandResult = command.CreateResult(); var commandLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); var commandOrchestration = await functionContext .CallActivityWithRetryAsync <string>(nameof(OrchestratorCommandDispatchActivity), command) .ConfigureAwait(true); commandResult = await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(commandOrchestration, command.CommandId.ToString(), command) .ConfigureAwait(true); } catch (Exception exc) { commandLog.LogError(exc, $"Processing command '{command.GetType().FullName}' ({command.CommandId}) Failed >>> {exc.Message}"); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { if (commandResult?.RuntimeStatus.IsUnknown() ?? false) { commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultAugmentActivity), commandResult) .ConfigureAwait(true); } await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); functionContext.SetOutput(commandResult); } }
public static Task <IReadOnlyDictionary <string, object> > CallDeploymentAsync(this IDurableOrchestrationContext functionContext, string deploymentActivityName, object deploymentActivityInput = default) { if (functionContext is null) { throw new System.ArgumentNullException(nameof(functionContext)); } if (string.IsNullOrEmpty(deploymentActivityName)) { throw new System.ArgumentException("message", nameof(deploymentActivityName)); } return(functionContext .CallSubOrchestratorWithRetryAsync <IReadOnlyDictionary <string, object> >(nameof(AzureDeploymentOrchestration), (functionContext.InstanceId, deploymentActivityName, deploymentActivityInput, default(string), default(string)))); }
internal static Task CallOperationAsync(this IDurableOrchestrationContext functionContext, string operationActivityName, object operationActivityInput = default) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } if (string.IsNullOrEmpty(operationActivityName)) { throw new ArgumentException("message", nameof(operationActivityName)); } return(functionContext .CallSubOrchestratorWithRetryAsync(nameof(OperationOrchestration), (operationActivityName, operationActivityInput, default(string)))); }
private static async Task FanOutFanInSubOrchestratorAsync(IDurableOrchestrationContext context, string functionName, RecipientsInfo recipientsInfo) { var tasks = new List <Task>(); // Fan-out foreach (var batchKey in recipientsInfo.BatchKeys) { var task = context.CallSubOrchestratorWithRetryAsync( functionName, FunctionSettings.DefaultRetryOptions, batchKey); tasks.Add(task); } // Fan-in await Task.WhenAll(tasks); }
public static async Task OrchestratorThrowWithRetry([OrchestrationTrigger] IDurableOrchestrationContext ctx) { string message = ctx.GetInput <string>(); RetryOptions options = new RetryOptions(TimeSpan.FromSeconds(5), 3); // Specify an explicit sub-orchestration ID that can be queried by the test driver. Guid subInstanceId = await ctx.CallActivityAsync <Guid>(nameof(TestActivities.NewGuid), null); ctx.SetCustomStatus(subInstanceId.ToString("N")); // This throw happens in the implementation of an orchestrator. await ctx.CallSubOrchestratorWithRetryAsync( nameof(TestOrchestrations.ThrowOrchestrator), options, subInstanceId.ToString("N"), message); }
public static Task RegisterProviderAsync(this IDurableOrchestrationContext functionContext, ProviderDocument provider = null, bool wait = true) { if (wait) { // if the caller request to wait for the provider registration // we will kick off the corresponding orchestration as a sub // orchestration instead of completely new one return(functionContext .CallSubOrchestratorWithRetryAsync(nameof(ProviderRegisterOrchestration), (provider, default(ProviderRegisterCommand)))); } functionContext .StartNewOrchestration(nameof(ProviderRegisterOrchestration), (provider, default(ProviderRegisterCommand))); return(Task .CompletedTask); }
internal static Task WaitForProjectCommandsAsync(this IDurableOrchestrationContext context, ICommand command) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (command is null) { throw new ArgumentNullException(nameof(command)); } if (command.ProjectId.HasValue) { return(context.CallSubOrchestratorWithRetryAsync(nameof(ProjectCommandSerializationOrchestrator), command)); } return(Task.CompletedTask); }
public async Task RunMainOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var events = context.GetInput <List <EventGridEventPayload> >(); List <Task> orchestrations = new List <Task>(); var retryOptions = new RetryOptions(TimeSpan.FromSeconds(15), 15) { BackoffCoefficient = 1.5, Handle = (ex) => ex.InnerException.Message == TriggerRetryException.DefaultMessage }; events.ForEach(delegate(EventGridEventPayload eventPayload) { orchestrations.Add(context.CallSubOrchestratorWithRetryAsync <bool>("ACI_Sub_Orchestrator_Func", retryOptions, eventPayload)); }); await Task.WhenAll(orchestrations); }
internal static async Task InitializeSubscriptionAsync(this IDurableOrchestrationContext orchestrationContext, Guid subscriptionId, bool waitFor = false) { var currentSubscriptionVersion = await orchestrationContext .GetSubscriptionVersionAsync(subscriptionId) .ConfigureAwait(true); if (currentSubscriptionVersion != TargetSubscriptionVersion) { if (waitFor) { await orchestrationContext .CallSubOrchestratorWithRetryAsync(nameof(SubscriptionInitializationOrchestration), subscriptionId) .ConfigureAwait(true); } else { orchestrationContext.StartNewOrchestration(nameof(SubscriptionInitializationOrchestration), subscriptionId); } } }
internal static async Task <TCommandResult> SendCommandAsync <TCommand, TCommandResult>(this IDurableOrchestrationContext functionContext, TCommand command, Provider provider) where TCommand : IProviderCommand where TCommandResult : ICommandResult { if (command is null) { throw new ArgumentNullException(nameof(command)); } if (provider is null) { throw new ArgumentNullException(nameof(provider)); } var providerResult = (TCommandResult)await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(nameof(CommandSendOrchestration), (command, provider)) .ConfigureAwait(true); return(providerResult); }
private static async Task RollbackAsync(IDurableOrchestrationContext functionContext, OrchestratorProjectCreateCommand command, ILogger log) { functionContext.SetCustomStatus($"Refreshing project", log); var project = (await functionContext .GetProjectAsync(command.ProjectId, allowUnsafe: true) .ConfigureAwait(true)) ?? command.Payload; functionContext.SetCustomStatus($"Rolling back project", log); var systemUser = await functionContext .CallActivityWithRetryAsync <UserDocument>(nameof(TeamCloudSystemUserActivity), null) .ConfigureAwait(true); var deleteCommand = new OrchestratorProjectDeleteCommand(systemUser, project); await functionContext .CallSubOrchestratorWithRetryAsync(nameof(OrchestratorProjectDeleteCommandOrchestration), deleteCommand) .ConfigureAwait(true); }
public async Task Orchestrator([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var activity = context.CreateActivityProxy <ISharedActivity>(); // 期限切れまで 30 日以内の証明書を取得する var certificates = await activity.GetExpiringCertificates(context.CurrentUtcDateTime); // 更新対象となる証明書がない場合は終わる if (certificates.Count == 0) { log.LogInformation("Certificates are not found"); return; } // スロットリング対策として 120 秒以内でジッターを追加する var jitter = (uint)context.NewGuid().GetHashCode() % 120; await context.CreateTimer(context.CurrentUtcDateTime.AddSeconds(jitter), CancellationToken.None); // 証明書の更新を行う foreach (var certificate in certificates) { log.LogInformation($"{certificate.Id} - {certificate.ExpiresOn}"); try { // 証明書の更新処理を開始 var certificatePolicyItem = await activity.GetCertificatePolicy(certificate.Name); await context.CallSubOrchestratorWithRetryAsync(nameof(SharedOrchestrator.IssueCertificate), _retryOptions, certificatePolicyItem); } catch (Exception ex) { // 失敗した場合はログに詳細を書き出して続きを実行する log.LogError($"Failed sub orchestration with DNS names = {string.Join(",", certificate.DnsNames)}"); log.LogError(ex.Message); } } }
public static async Task <ShippingPrice> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var input = context.GetInput <SagaContext>(); // activity to check if we ship to the specified continent if (!await context.CallActivityWithRetryAsync <bool>("IsContinentSupportedWithRetry", RetryOptions, input.Continent)) { return(new ShippingPrice() { Shippable = false, Message = "We aren't able to ship to your location" }); } // activity to get proper orchestrator for continent for shipping partner var supplierOrchestratorToRun = await context.CallActivityWithRetryAsync <string>("GetSupplierOrchestratorForContinentWithRetry", RetryOptions, input.Continent); // orchestrator to get the price for the shipping address var priceForShipment = await context.CallSubOrchestratorWithRetryAsync <decimal>( $"{supplierOrchestratorToRun}OrchestratorWithRetry", RetryOptions, input); // activity to publish event for Sales / marketing await context.CallActivityWithRetryAsync("PublishCalculatedPriceActivityWithRetry", RetryOptions, (input, priceForShipment)); return(new ShippingPrice() { Shippable = true, Price = priceForShipment }); }
public static async Task <string> AllOrchestratorActivityActions([OrchestrationTrigger] IDurableOrchestrationContext ctx) { EntityId input = ctx.GetInput <EntityId>(); var stringInput = input.ToString(); RetryOptions options = new RetryOptions(TimeSpan.FromSeconds(5), 3); await ctx.CreateTimer(ctx.CurrentUtcDateTime, CancellationToken.None); await ctx.CallActivityAsync <string>(nameof(TestActivities.Hello), stringInput); await ctx.CallActivityWithRetryAsync <string>(nameof(TestActivities.Hello), options, stringInput); await ctx.CallSubOrchestratorAsync <string>(nameof(TestOrchestrations.SayHelloInline), stringInput); await ctx.CallSubOrchestratorWithRetryAsync <string>(nameof(TestOrchestrations.SayHelloWithActivity), options, stringInput); ctx.StartNewOrchestration(nameof(TestOrchestrations.SayHelloWithActivityWithDeterministicGuid), stringInput); ctx.SignalEntity(input, "count"); ctx.SetCustomStatus("AllAPICallsUsed"); await ctx.CallHttpAsync(null); return("TestCompleted"); }
public static async Task Run( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, [DurableClient] IDurableClient durableClient, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } if (durableClient is null) { throw new ArgumentNullException(nameof(durableClient)); } var commandMessage = functionContext.GetInput <ProviderCommandMessage>() ?? throw new ArgumentException("Command message is null", nameof(functionContext)); var command = commandMessage.Command ?? throw new ArgumentException("Command message does not contain a command", nameof(functionContext)); var commandResult = command.CreateResult(); var commandLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); var commandOrchestrationName = await functionContext .CallActivityWithRetryAsync <string>(nameof(ProviderCommandDispatchActivity), command) .ConfigureAwait(true); var commandOrchestrationInstanceId = CommandHandler.GetCommandOrchestrationInstanceId(command); if (string.IsNullOrEmpty(commandOrchestrationName)) { commandLog .LogInformation($"Dispatching command '{command.GetType().FullName}' ({command.CommandId}) >>> FALLBACK ({commandOrchestrationInstanceId})"); commandResult = await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(nameof(ProviderCommandFallbackOrchestration), commandOrchestrationInstanceId, command) .ConfigureAwait(true); } else { commandLog .LogInformation($"Dispatching command '{command.GetType().FullName}' ({commandMessage.CommandId}) >>> {commandOrchestrationName} ({commandOrchestrationInstanceId})"); commandResult = await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(commandOrchestrationName, commandOrchestrationInstanceId, command) .ConfigureAwait(true); } commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(ProviderCommandResultAugmentActivity), (commandResult, commandOrchestrationInstanceId)) .ConfigureAwait(true); } catch (Exception exc) { commandLog.LogError(exc, $"Processing command '{command.GetType().FullName}' ({command.CommandId}) Failed >>> {exc.Message}"); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { try { await functionContext .CallActivityWithRetryAsync(nameof(ProviderCommandResultSendActivity), (commandResult, commandMessage.CallbackUrl)) .ConfigureAwait(true); } catch (Exception exc) { commandLog.LogError(exc, $"Sending result for command '{command.GetType().FullName}' ({command.CommandId}) Failed >>> {exc.Message}"); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); functionContext.SetOutput(commandResult); } } }
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } var(provider, command) = functionContext .GetInput <(Provider, ProviderRegisterCommand)>(); TeamCloudInstance teamCloud = null; try { if (command is null) { // no command was given !!! // restart the orchestration // with a new command instance. var systemUser = await functionContext .CallActivityWithRetryAsync <User>(nameof(TeamCloudUserActivity), null) .ConfigureAwait(true); functionContext .ContinueAsNew((provider, new ProviderRegisterCommand(systemUser, new ProviderConfiguration()))); } else if (provider is null) { // no provider was given !!! // fan out registration with // one orchestration per provider. functionContext.SetCustomStatus($"Register providers ...", log); teamCloud = await functionContext .GetTeamCloudAsync() .ConfigureAwait(true); var tasks = teamCloud.Providers .Select(provider => functionContext.CallSubOrchestratorWithRetryAsync(nameof(OrchestratorProviderRegisterCommandOrchestration), (provider, command))); await Task .WhenAll(tasks) .ConfigureAwait(true); } else { teamCloud = await functionContext .GetTeamCloudAsync() .ConfigureAwait(true); command.Payload .TeamCloudApplicationInsightsKey = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY"); command.Payload .Properties = teamCloud.Properties.Override(provider.Properties); var commandResult = await functionContext .SendCommandAsync <ProviderRegisterCommand, ProviderRegisterCommandResult>(command, provider) .ConfigureAwait(true); if (commandResult?.Result != null) { using (await functionContext.LockAsync(teamCloud).ConfigureAwait(true)) { teamCloud = await functionContext .GetTeamCloudAsync() .ConfigureAwait(true); provider = teamCloud.Providers .FirstOrDefault(p => p.Id == provider.Id); if (provider is null) { log.LogWarning($"Provider '{provider.Id}' registration skipped - provider no longer exists"); } else { provider.PrincipalId = commandResult.Result.PrincipalId; provider.Registered = functionContext.CurrentUtcDateTime; provider.Properties = provider.Properties.Override(commandResult.Result.Properties); teamCloud = await functionContext .SetTeamCloudAsync(teamCloud) .ConfigureAwait(true); functionContext.SetCustomStatus($"Provider '{provider.Id}' registration succeeded", log); } } } } } catch (Exception exc) { if (provider != null) { functionContext.SetCustomStatus($"Failed to register provider '{provider.Id}' - {exc.Message}", log, exc); } else if (command != null) { functionContext.SetCustomStatus($"Failed to register providers - {exc.Message}", log, exc); } else { functionContext.SetCustomStatus($"Failed to initiate provider registration - {exc.Message}", log, exc); } } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var notificationDataEntity = context.GetInput <NotificationDataEntity>(); if (!context.IsReplaying) { log.LogInformation($"Start to prepare to send the notification {notificationDataEntity.Id}!"); } try { if (!context.IsReplaying) { log.LogInformation("About to store message content."); } await context.CallActivityWithRetryAsync( FunctionNames.StoreMessageActivity, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to sync recipients."); } var recipientsInfo = await context.CallSubOrchestratorWithRetryAsync <RecipientsInfo>( FunctionNames.SyncRecipientsOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); // Proactive Installation if (recipientsInfo.HasRecipientsPendingInstallation) { if (!context.IsReplaying) { log.LogInformation("About to create 1:1 conversations for recipients if required."); } // Update notification status. await context.CallActivityWithRetryAsync( FunctionNames.UpdateNotificationStatusActivity, FunctionSettings.DefaultRetryOptions, (recipientsInfo.NotificationId, NotificationStatus.InstallingApp)); // Fan Out/Fan In Conversation orchestrator. await FanOutFanInSubOrchestratorAsync(context, FunctionNames.TeamsConversationOrchestrator, recipientsInfo); } if (!context.IsReplaying) { log.LogInformation("About to send messages to send queue."); } // Update notification status. await context.CallActivityWithRetryAsync( FunctionNames.UpdateNotificationStatusActivity, FunctionSettings.DefaultRetryOptions, (notificationDataEntity.Id, NotificationStatus.Sending)); // Update Total recipient count. await context.CallActivityWithRetryAsync( FunctionNames.DataAggregationTriggerActivity, FunctionSettings.DefaultRetryOptions, (notificationDataEntity.Id, recipientsInfo.TotalRecipientCount)); // Fan-out/ Fan-in send queue orchestrator. await FanOutFanInSubOrchestratorAsync(context, FunctionNames.SendQueueOrchestrator, recipientsInfo); log.LogInformation($"PrepareToSendOrchestrator successfully completed for notification: {notificationDataEntity.Id}!"); } catch (Exception ex) { var errorMessage = $"PrepareToSendOrchestrator failed for notification: {notificationDataEntity.Id}. Exception Message: {ex.Message}"; log.LogError(ex, errorMessage); await context.CallActivityWithRetryAsync( FunctionNames.HandleFailureActivity, FunctionSettings.DefaultRetryOptions, (notificationDataEntity, ex)); } }
public static async Task RunOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext orchestrationContext, ILogger log) { if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } var functionInput = orchestrationContext.GetInput <Input>(); try { if (functionInput.Command is null) { // no command was given !!! // restart the orchestration // with a new command instance. orchestrationContext.SetCustomStatus("Creating command", log); var systemUser = await orchestrationContext .CallActivityWithRetryAsync <UserDocument>(nameof(TeamCloudSystemUserActivity), null) .ConfigureAwait(true); functionInput.Command = new ProviderRegisterCommand ( systemUser.PopulateExternalModel(), new ProviderConfiguration() ); orchestrationContext .ContinueAsNew(functionInput); } else if (functionInput.Provider is null) { // no provider was given !!! // fan out registration with // one orchestration per provider. var providers = await orchestrationContext .ListProvidersAsync() .ConfigureAwait(true); if (providers.Any()) { orchestrationContext.SetCustomStatus($"Register provider/s", log); var tasks = providers .Select(provider => orchestrationContext.CallSubOrchestratorWithRetryAsync(nameof(ProviderRegisterOrchestration), new Input() { Provider = provider, Command = functionInput.Command })); await Task .WhenAll(tasks) .ConfigureAwait(true); } } else { functionInput.Command.Payload .TeamCloudApplicationInsightsKey = await orchestrationContext .GetInstrumentationKeyAsync() .ConfigureAwait(true); functionInput.Command.Payload .Properties = functionInput.Provider.Properties; orchestrationContext.SetCustomStatus($"Sending command", log); var commandResult = await orchestrationContext .SendProviderCommandAsync <ProviderRegisterCommand, ProviderRegisterCommandResult>(functionInput.Command, functionInput.Provider) .ConfigureAwait(true); if (commandResult.RuntimeStatus == CommandRuntimeStatus.Completed) { using (await orchestrationContext.LockContainerDocumentAsync(functionInput.Provider).ConfigureAwait(true)) { functionInput.Provider = await orchestrationContext .GetProviderAsync(functionInput.Provider.Id) .ConfigureAwait(true); if (functionInput.Provider is null) { log.LogWarning($"Provider registration skipped - provider no longer exists"); } else { functionInput.Provider.PrincipalId = commandResult.Result.PrincipalId; functionInput.Provider.CommandMode = commandResult.Result.CommandMode; functionInput.Provider.Registered = orchestrationContext.CurrentUtcDateTime; functionInput.Provider.EventSubscriptions = commandResult.Result.EventSubscriptions; functionInput.Provider.ResourceProviders = commandResult.Result.ResourceProviders; functionInput.Provider.Properties = functionInput.Provider.Properties.Override(commandResult.Result.Properties); orchestrationContext.SetCustomStatus($"Updating provider", log); functionInput.Provider = await orchestrationContext .SetProviderAsync(functionInput.Provider) .ConfigureAwait(true); if (functionInput.Provider.PrincipalId.HasValue) { orchestrationContext.SetCustomStatus($"Resolving provider identity", log); var providerUser = await orchestrationContext .GetUserAsync(functionInput.Provider.PrincipalId.Value.ToString(), allowUnsafe : true) .ConfigureAwait(true); if (providerUser is null) { providerUser = new UserDocument { Id = functionInput.Provider.PrincipalId.Value.ToString(), Role = TeamCloudUserRole.Provider, UserType = UserType.Provider }; orchestrationContext.SetCustomStatus($"Granting provider access", log); _ = await orchestrationContext .SetUserTeamCloudInfoAsync(providerUser, allowUnsafe : true) .ConfigureAwait(true); } } } } orchestrationContext.SetCustomStatus($"Provider registered", log); } else { var exception = commandResult.Errors .ToException(); throw exception ?? new OperationErrorException($"Provider registration ended in runtime status '{commandResult.RuntimeStatus}'"); } } } catch (Exception exc) { if (functionInput.Provider != null) { orchestrationContext.SetCustomStatus($"Failed to register provider '{functionInput.Provider.Id}' - {exc.Message}", log, exc); } else if (functionInput.Command != null) { orchestrationContext.SetCustomStatus($"Failed to register providers - {exc.Message}", log, exc); } else { orchestrationContext.SetCustomStatus($"Failed to initiate provider registration - {exc.Message}", log, exc); } } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var notificationDataEntity = context.GetInput <NotificationDataEntity>(); if (!context.IsReplaying) { log.LogInformation($"Start to prepare to send the notification {notificationDataEntity.Id}!"); } try { if (!context.IsReplaying) { log.LogInformation("About to store message content."); } await context.CallActivityWithRetryAsync( FunctionNames.StoreMessageActivity, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to sync recipients."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.SyncRecipientsOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to create conversation for recipients if required."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.TeamsConversationOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); if (!context.IsReplaying) { log.LogInformation("About to send messages to send queue."); } await context.CallSubOrchestratorWithRetryAsync( FunctionNames.SendQueueOrchestrator, FunctionSettings.DefaultRetryOptions, notificationDataEntity); log.LogInformation($"PrepareToSendOrchestrator successfully completed for notification: {notificationDataEntity.Id}!"); } catch (Exception ex) { var errorMessage = $"PrepareToSendOrchestrator failed for notification: {notificationDataEntity.Id}. Exception Message: {ex.Message}"; log.LogError(ex, errorMessage); await context.CallActivityWithRetryAsync( FunctionNames.HandleFailureActivity, FunctionSettings.DefaultRetryOptions, (notificationDataEntity, ex)); } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { var matchingFrequnecy = context.InstanceId; if (!context.IsReplaying) { log.LogInformation($"Start to prepare pair up recipients for resource group entities based on frequency :{matchingFrequnecy}!"); } try { if (!context.IsReplaying) { log.LogInformation("About to fetch resource group entities."); } // fetch all resource groups based on matching frequency. var resourceGroupEntities = await context.CallActivityWithRetryAsync <IEnumerable <EmployeeResourceGroupEntity> >( FunctionNames.GetResourceGroupEntitiesActivity, FunctionSettings.DefaultRetryOptions, matchingFrequnecy); if (resourceGroupEntities == null || resourceGroupEntities.Count() == 0) { log.LogInformation("Resource group entities not found as per the matching frequency"); return; } log.LogInformation($"About to process {resourceGroupEntities.Count()} resource group entities."); foreach (var entity in resourceGroupEntities) { try { if (!context.IsReplaying) { log.LogInformation("About to sync and send pair up batches to queue."); } // start sub-orchestrator to sync recipients and send pair-up matches to queue. await context.CallSubOrchestratorWithRetryAsync( FunctionNames.SyncRecipientsAndSendBatchesToQueueOrchestrator, FunctionSettings.DefaultRetryOptions, entity); log.LogInformation($"Successfully send pair up batches to queue for team: {entity.TeamId}."); } catch (Exception ex) { log.LogInformation($"Unable to send pair up batches to queue for team :{entity.TeamId} {ex.Message}."); } } log.LogInformation($"PrepareBatchesToSendOrchestrator successfully completed for resource groups of matching frequency: {matchingFrequnecy}!"); } catch (Exception ex) { var errorMessage = $"PrepareBatchesToSendOrchestrator failed for resource groups of matching frequency: {matchingFrequnecy} Exception Message: {ex.Message}!"; log.LogError(ex, errorMessage); } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext orchestrationContext, ILogger log) { if (orchestrationContext is null) { throw new ArgumentNullException(nameof(orchestrationContext)); } var command = orchestrationContext.GetInput <ICommand>(); var commandResult = command.CreateResult(); var commandLog = orchestrationContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { orchestrationContext.SetCustomStatus("Auditing command", log); await orchestrationContext .AuditAsync(command, commandResult) .ConfigureAwait(true); orchestrationContext.SetCustomStatus("Processing command", log); commandResult = await orchestrationContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(OrchestratorCommandOrchestrationHandler.GetCommandOrchestrationName(command), command.CommandId.ToString(), command) .ConfigureAwait(true); } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { try { orchestrationContext.SetCustomStatus("Augmenting command result", log); commandResult = await orchestrationContext .CallActivityWithRetryAsync <ICommandResult>(nameof(CommandResultAugmentActivity), commandResult) .ConfigureAwait(true); } catch (Exception exc) { commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } orchestrationContext.SetCustomStatus("Auditing command result", log); await orchestrationContext .AuditAsync(command, commandResult) .ConfigureAwait(true); var commandException = commandResult.Errors?.ToException(); if (commandException is null) { orchestrationContext.SetCustomStatus($"Command succeeded", log); } else { orchestrationContext.SetCustomStatus($"Command failed: {commandException.Message}", log, commandException); } orchestrationContext.SetOutput(commandResult); } }
public static async Task Run( [OrchestrationTrigger] IDurableOrchestrationContext functionContext, [DurableClient] IDurableClient durableClient, ILogger log) { if (functionContext is null) { throw new ArgumentNullException(nameof(functionContext)); } if (durableClient is null) { throw new ArgumentNullException(nameof(durableClient)); } var commandMessage = functionContext.GetInput <ProviderCommandMessage>() ?? throw new ArgumentException("Command message is null", nameof(functionContext)); var command = commandMessage.Command ?? throw new ArgumentException("Command message does not contain a command", nameof(functionContext)); var commandResult = command.CreateResult(); var commandLog = functionContext.CreateReplaySafeLogger(log ?? NullLogger.Instance); try { await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); var commandOrchestrationName = await functionContext .CallActivityWithRetryAsync <string>(nameof(ProviderCommandDispatchActivity), command) .ConfigureAwait(true); var commandOrchestrationInstanceId = CommandHandler.GetCommandOrchestrationInstanceId(command); if (string.IsNullOrEmpty(commandOrchestrationName)) { commandLog .LogInformation($"Dispatching command '{command.GetType().FullName}' ({command.CommandId}) >>> FALLBACK ({commandOrchestrationInstanceId})"); commandResult = await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(nameof(ProviderCommandFallbackOrchestration), commandOrchestrationInstanceId, command) .ConfigureAwait(true); } else { commandLog .LogInformation($"Dispatching command '{command.GetType().FullName}' ({commandMessage.CommandId}) >>> {commandOrchestrationName} ({commandOrchestrationInstanceId})"); commandResult = await functionContext .CallSubOrchestratorWithRetryAsync <ICommandResult>(commandOrchestrationName, commandOrchestrationInstanceId, command) .ConfigureAwait(true); } do { // there is a chance that the suborchestration used to agument the command result // doesn't reflect the final runtime status (completed / failed / canceled) because // of timing issues in the durable functions runtime. to void a none final runtime // status reported back to the orchestrator we loop / wait for this runtime status. commandResult = await functionContext .CallActivityWithRetryAsync <ICommandResult>(nameof(ProviderCommandResultAugmentActivity), (commandResult, commandOrchestrationInstanceId)) .ConfigureAwait(true); }while (commandResult.RuntimeStatus.IsActive()); } catch (Exception exc) { commandLog.LogError(exc, $"Processing command '{command.GetType().FullName}' ({command.CommandId}) Failed >>> {exc.Message}"); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { try { await functionContext .CallActivityWithRetryAsync(nameof(ProviderCommandResultSendActivity), (commandResult, commandMessage.CallbackUrl)) .ConfigureAwait(true); } catch (Exception exc) { commandLog.LogError(exc, $"Sending result for command '{command.GetType().FullName}' ({command.CommandId}) Failed >>> {exc.Message}"); commandResult ??= command.CreateResult(); commandResult.Errors.Add(exc); } finally { await functionContext .AuditAsync(command, commandResult) .ConfigureAwait(true); functionContext.SetOutput(commandResult); } } }