Esempio n. 1
0
        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-----------------");
        }
Esempio n. 3
0
        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);
        }
Esempio n. 5
0
        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);
                }
            }
        }
Esempio n. 6
0
        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);
        }
Esempio n. 8
0
        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);
            }
        }
Esempio n. 10
0
        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))));
        }
Esempio n. 11
0
        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);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
        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);
        }
Esempio n. 17
0
        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);
                }
            }
        }
Esempio n. 18
0
        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);
        }
Esempio n. 19
0
        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);
        }
Esempio n. 20
0
        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);
                }
            }
        }
Esempio n. 24
0
        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);
                }
            }
        }
Esempio n. 27
0
        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));
            }
        }
Esempio n. 28
0
        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);
            }
        }
Esempio n. 30
0
        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);
                }
            }
        }