예제 #1
0
        public async Task Run(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger logger)
        {
            var input = context.GetInput <NotifySupportOrchestratorInput>();

            if (input.SupportContacts == null)
            {
                // Let's get the support contacts from storage.
                var supportContacts = await context.CallActivityAsync <IEnumerable <SupportContactEntity> >(
                    nameof(GetSupportContactActivity),
                    "A");

                input.SupportContacts = supportContacts.ToArray();
            }

            var notificationOrchestratorInput = SendNotificationOrchestratorInputBuilder.Build(input);

            var notificationResult = await context.CallSubOrchestratorAsync <SendNotificationOrchestratorResult>(
                nameof(SendNotificationOrchestrator),
                notificationOrchestratorInput);

            if (!notificationResult.CallbackReceived &&
                notificationOrchestratorInput.SupportContact != input.SupportContacts.Last())
            {
                // Calls have not been answered, let's try the next contact.
                input.SupportContactIndex++;
                logger.LogInformation($"=== Next Contact={input.SupportContacts[input.SupportContactIndex].PhoneNumber} ===");
                context.ContinueAsNew(input);
            }
            else
            {
                logger.LogInformation($"=== Completed {nameof(NotifySupportOrchestrator)} for {notificationResult.PhoneNumber} with callback received={notificationResult.CallbackReceived} on attempt={notificationResult.Attempt}. ===");
            }
        }
예제 #2
0
        private static async Task <ICommandResult> SwitchCommandAsync(IDurableOrchestrationContext orchestrationContext, Input functionContext, ICommandResult commandResult, ILogger log)
        {
            try
            {
                await orchestrationContext
                .AuditAsync(functionContext.Command, commandResult, functionContext.Provider)
                .ConfigureAwait(true);

                orchestrationContext.SetCustomStatus($"Switching command", log);

                var project = await orchestrationContext
                              .GetProjectAsync(functionContext.Command.ProjectId, allowUnsafe : true)
                              .ConfigureAwait(true);

                functionContext.Command = new ProviderProjectUpdateCommand(functionContext.Command.User as User, project.PopulateExternalModel(), functionContext.Command.CommandId);

                orchestrationContext.ContinueAsNew(functionContext);
            }
            catch (Exception exc)
            {
                orchestrationContext.SetCustomStatus($"Switching command failed: {exc.Message}", log, exc);

                commandResult ??= functionContext.Command.CreateResult();
                commandResult.Errors.Add(exc);
            }

            return(commandResult);
        }
        public async Task <object> Run(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var input = context.GetInput <Input>();

            try
            {
                var output = await context.CallActivityAsync <object>(input.ActivityFunctionName, input.ActivityFunctionInput);

                await this.circuitBreakerClient.RecordSuccess(input.CircuitBreakerOptions.CircuitBreakerId, log, context);

                return(output);
            }
            catch (Exception exception)
            {
                await this.circuitBreakerClient.RecordFailure(input.CircuitBreakerOptions.CircuitBreakerId, log, context);

                var handled = await HandleException(exception, context);

                if (handled)
                {
                    context.ContinueAsNew(input);
                    return(null);
                }
                else
                {
                    throw;
                }
            }
        }
        public static async Task <int> Counter([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            int    currentValue = ctx.GetInput <int>();
            string operation    = await ctx.WaitForExternalEvent <string>("operation");

            bool done = false;

            switch (operation?.ToLowerInvariant())
            {
            case "incr":
                currentValue++;
                break;

            case "decr":
                currentValue--;
                break;

            case "end":
                done = true;
                break;
            }

            // Allow clients to track the current value.
            ctx.SetCustomStatus(currentValue);

            if (!done)
            {
                ctx.ContinueAsNew(currentValue, preserveUnprocessedEvents: true);
            }

            return(currentValue);
        }
예제 #5
0
        public async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            try
            {
                //var parallelTasks = new List<Task<int>>();

                // Get a list of N callLog items to process in parallel.
                var workBatch = await context.CallActivityAsync <IList <CallLog> >("PostCallCleanupEternalOrchestrator_GetCallLog", null);

                log.LogInformation($"PostCallCleanupEternalOrchestrator: WorkBatch items to process: {JsonConvert.SerializeObject(workBatch)}");

                var tasks = new Task <CallLog> [workBatch.Count];
                for (int i = 0; i < workBatch.Count; i++)
                {
                    tasks[i] = context.CallActivityAsync <CallLog>("PostCallCleanupEternalOrchestrator_PostCallCleanup", workBatch[i]);
                }
            }
            catch (Exception ex)
            {
                log.LogWarning(ex, $"PostCallCleanupEternalOrchestrator: An error occurred while processing orchestrator. Details: {ex.Message}");
            }
            finally
            {
                // sleep for n minutes before running again
                int      minuteInterval = int.Parse(_configuration["PostCallCleanupCheckMinuteInterval"] ?? "5");
                DateTime nextCleanup    = context.CurrentUtcDateTime.AddMinutes(minuteInterval);
                await context.CreateTimer(nextCleanup, CancellationToken.None);

                log.LogInformation("Restarting orchestrator");
                context.ContinueAsNew(null);
            }
        }
        public async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            log = context.CreateReplaySafeLogger(log);

            // Real life scenario would be to create a new report every day at midnight
            // DateTime endTime = context.CurrentUtcDateTime.AddDays(1).Date;

            DateTime reportCreationTime  = context.CurrentUtcDateTime.AddSeconds(15);
            var      reportCreationTimer = context.CreateTimer(reportCreationTime, CancellationToken.None);

            var reportingCancelationRequest = context.WaitForExternalEvent("CancelReportingTask");

            var completedTask = await Task.WhenAny(reportCreationTimer, reportingCancelationRequest);

            if (completedTask == reportCreationTimer)
            {
                await context.CallActivityAsync(nameof(ReportCreationActivity), null);

                log.LogInformation("Starting a new instance cycle");
                // Eternal orchestration until canceled
                context.ContinueAsNew(null);
            }
            else
            {
                log.LogInformation("Reporting task cancelation was requested");
            }
        }
        public async Task Run(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger logger)
        {
            await context.CreateTimer(
                context.CurrentUtcDateTime.AddHours(1),
                CancellationToken.None);

            context.ContinueAsNew(null);
        }
예제 #8
0
        public static async Task CallOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            var startArgs = await ctx.WaitForExternalEvent <StartOrchestrationArgs>("StartOrchestration");

            await ctx.CallSubOrchestratorAsync <object>(
                startArgs.FunctionName,
                startArgs.InstanceId,
                startArgs.Input);

            ctx.ContinueAsNew(null, preserveUnprocessedEvents: true);
        }
예제 #9
0
        public static async Task <bool> Run([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger logger)
        {
            var hostId = context.GetInput <EntityId>();

            logger = context.CreateReplaySafeLogger(logger);

            var state = await context.CallActivityAsync <EntityStateResponse <HostEntity> >(nameof(GetHostState), hostId);

            if (!state.EntityExists)
            {
                logger.LogError("Attempted to start watch dog for a non-existing host entity: {hostId}", hostId);
                throw new Exception("Failed to start watch dog for non-existing entity");
            }

            if (context.InstanceId != HostEntity.calculateHash(state.EntityState.IpAddress))
            {
                throw new Exception("violent suicide committed on watchdog!");
            }

            if (state.EntityState.ipv4Support || state.EntityState.ipv6Support)
            {
                context.SignalEntity(HostList.Id, HostList.AddHost, hostId);
                logger.LogInformation("Adding {hostId} to active hosts", hostId);
            }
            else
            {
                context.SignalEntity(HostList.Id, HostList.RemoveHost, hostId);
                logger.LogInformation("Removing {hostId} from active hosts", hostId);
            }

            var nextCheck = state.EntityState.DnsUptime switch
            {
                { } v when v < 0.2m => TimeSpan.FromDays(1),
                { } v when v >= 0.2m && v < 0.75m => TimeSpan.FromHours(12 + new Random().Next(-1, 1)),
                { } v when v >= 0.75m => TimeSpan.FromMinutes(60 + new Random().Next(-5, 5)),
                _ => TimeSpan.FromHours(1)
            };

#if DEBUG
            nextCheck = TimeSpan.FromMinutes(5);
#endif

            await context.CreateTimer(context.CurrentUtcDateTime + nextCheck, CancellationToken.None);

            var host = context.CreateEntityProxy <IHostEntity>(hostId);

            await host.CheckUp();

            context.ContinueAsNew(hostId);

            return(true);
        }
    }
예제 #10
0
    public static async Task ContinueAsNew(this IDurableOrchestrationContext orchestration, object input, TimeSpan delay, bool preserveUnprocessedEvents = false)
    {
        if (orchestration is null)
        {
            throw new ArgumentNullException(nameof(orchestration));
        }

        await orchestration
        .CreateTimer(delay)
        .ConfigureAwait(true);

        orchestration.ContinueAsNew(input, preserveUnprocessedEvents);
    }
예제 #11
0
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger logger)
        {
            logger = context.CreateReplaySafeLogger(logger);

            var expiration = context.GetInput <DateTime>();

            var minDelay   = TimeSpan.FromSeconds(10);
            var maxDelay   = TimeSpan.FromSeconds(30);
            var delayDelta = expiration - context.CurrentUtcDateTime;
            var waitTime   = TimeSpan.FromSeconds(Math.Clamp(delayDelta.TotalSeconds, minDelay.TotalSeconds, maxDelay.TotalSeconds));
            var wakeupTime = context.CurrentUtcDateTime + waitTime;

            logger.LogInformation($">>>>>>      [ORC] Orchestration begins with expiration at { expiration }, waitTime { waitTime }, next wakeup at { wakeupTime }");

            using (var cts = new CancellationTokenSource())
            {
                var timerTask = context.CreateTimer(wakeupTime, cts.Token);
                var dataTask  = context.WaitForExternalEvent <string>(DataEventName);

                var winner = await Task.WhenAny(dataTask, timerTask);

                if (winner == dataTask)
                {
                    cts.Cancel();

                    var data = await dataTask;

                    logger.LogInformation($">>>>>>      [ORC] Data Event Triggered, data = { data }");

                    var result = await context.CallActivityAsync <string>(nameof(SayHello), data);

                    logger.LogInformation($">>>>>>      [ORC] Activity result { result }");
                }
                else
                {
                    logger.LogInformation(">>>>>>      [ORC] Timer Triggered");

                    if (context.CurrentUtcDateTime >= expiration)
                    {
                        logger.LogInformation(">>>>>>      [ORC] Orchestration expired");
                        return;
                    }
                }

                logger.LogInformation(">>>>>>      [ORC] Restarting for another round");
                context.ContinueAsNew(expiration, true);
            }
        }
예제 #12
0
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var message = JObject.Parse(context.GetInput <string>());

            var maxRetryNumber           = (int)message[MessagePropertyNames.MaxRetryNumber];
            var renewalIntervalInSeconds = (int)message[MessagePropertyNames.RenewalIntervalInSeconds];

            var contextInstanceId = context.InstanceId;

            log.LogInformation($"ID '{contextInstanceId}': Iteration {message[MessagePropertyNames.RetryCount]}/{maxRetryNumber} started.");

            DateTime deadline = context.CurrentUtcDateTime.Add(TimeSpan.FromSeconds(renewalIntervalInSeconds));

            using (var cts = new CancellationTokenSource())
            {
                Task terminationTask = context.WaitForExternalEvent(TerminationEventName);
                Task timeoutTask     = context.CreateTimer(deadline, cts.Token);

                Task winner = await Task.WhenAny(terminationTask, timeoutTask);

                if (winner == terminationTask)
                {
                    // success case
                    log.LogInformation($"ID '{contextInstanceId}': Lock-handling stopped by using instance.");

                    cts.Cancel();
                }
                else if ((int)message[MessagePropertyNames.RetryCount] < maxRetryNumber)
                {
                    // timeout case
                    log.LogInformation($"ID '{contextInstanceId}': Interval reached for lock-renewal.");

                    (bool terminated, string nextMessageJson) = await context.CallActivityAsync <(bool, string)>(nameof(RenewLockActivity), (contextInstanceId, message));

                    if (!terminated)
                    {
                        log.LogInformation($"ID '{contextInstanceId}': Scheduling next iteration.");

                        context.ContinueAsNew(nextMessageJson);
                    }
                }
                else
                {
                    log.LogInformation($"ID '{contextInstanceId}': Maximal number of cycles reached. Aborting lock-handling.");
                }
            }
        }
예제 #13
0
        public async Task Periodic_Cleanup_Loop(
            [OrchestrationTrigger] IDurableOrchestrationContext context)
        {
            var expire = context.GetInput <Expire>();
            await context.CallActivityAsync(nameof(this.CleanUpNotification), "CleanUp!");

            DateTime nextCleanup = context.CurrentUtcDateTime.AddSeconds(10);

            if (expire.Value > nextCleanup)
            {
                await context.CreateTimer(nextCleanup, CancellationToken.None);

                context.ContinueAsNew(expire);
            }
        }
        public static async Task Orchestration(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var args = context.GetInput <HttpTriggerArgs>();

            using (var cts = new CancellationTokenSource())
            {
                await context.WaitForExternalEvent("WakeUp", TimeSpan.FromSeconds(30));

                var entityId         = new EntityId(nameof(DeviceEntity), args.DeviceId);
                var onlineStatusTask = await context.CallEntityAsync <string>(entityId, nameof(DeviceEntity.Getonline));
            }

            context.ContinueAsNew(args, false);
        }
예제 #15
0
        public static async Task <string> ContinueAsNew_Repro285([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            var input = ctx.GetInput <int>();

            if (input == 0)
            {
                ctx.ContinueAsNew(1);

                return("continue as new");
            }
            else if (input == 1)
            {
                await ctx.CreateTimer <object>(ctx.CurrentUtcDateTime + TimeSpan.FromSeconds(1), null, CancellationToken.None);
            }

            return("ok");
        }
        public static async Task WaitingOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext ctx,
            ILogger log)
        {
            var orchestratorArgs = ctx.GetInput <OrchestratorArgs>();

            // Using an entity as a cache for the data of the device like
            // - OfflineAfter, static metadata, typically coming from a device registry (loaded during initialization of entity)
            // - LastMessageReceived, 'hot' data, not essential for current PoC but could be usefull later on
            var entity = new EntityId(nameof(DeviceEntity), orchestratorArgs.DeviceId);

            var offlineAfter = await ctx.CallEntityAsync <TimeSpan>(entity, "GetOfflineAfter");

            var lastActivity = await ctx.CallEntityAsync <DateTime?>(entity, "GetLastMessageReceived");

            if (!ctx.IsReplaying && (!lastActivity.HasValue || ctx.CurrentUtcDateTime - lastActivity > offlineAfter))
            {
                // This runs for the first message ever for a device id
                // Also, after a device has gone offline and comes back online, this orchestrator starts again Last Activity should then be longer ago then the offline after
                log.LogInformation($"Device {orchestratorArgs.DeviceId}, was unkown or offline and is now online!");
                await ctx.CallActivityAsync(nameof(SendStatusUpdate), new StatusUpdateArgs(orchestratorArgs.DeviceId, true));
            }

            try
            {
                await ctx.WaitForExternalEvent("MessageReceived", offlineAfter);

                if (!ctx.IsReplaying)
                {
                    log.LogInformation($"Message received for device {orchestratorArgs.DeviceId}, resetting timeout of {offlineAfter.TotalSeconds} seconds offline detection...");
                }
                ctx.ContinueAsNew(orchestratorArgs);
                return;
            }
            catch (TimeoutException)
            {
                if (!ctx.IsReplaying)
                {
                    log.LogWarning($"Device {orchestratorArgs.DeviceId}, is now offline after waiting for {offlineAfter.TotalSeconds} seconds");
                }
                await ctx.CallActivityAsync(nameof(SendStatusUpdate), new StatusUpdateArgs(orchestratorArgs.DeviceId, false));

                return;
            }
        }
        public static async Task <int> PeriodicTask(
            [OrchestrationTrigger] IDurableOrchestrationContext ctx,
            ILogger log)
        {
            log = ctx.CreateReplaySafeLogger(log);

            var timesRun = ctx.GetInput <int>();

            timesRun++;
            log.LogInformation($"Starting the PeriodicTask activity {ctx.InstanceId}, {timesRun}");
            await ctx.CallActivityAsync("A_PeriodicActivity", timesRun);

            var nextRun = ctx.CurrentUtcDateTime.AddSeconds(30);
            await ctx.CreateTimer(nextRun, CancellationToken.None);

            ctx.ContinueAsNew(timesRun);
            return(timesRun);
        }
예제 #18
0
        public static async Task IotHubScaleOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            log.LogInformation("IotHubScaleOrchestrator started");

            // launch and wait on the "worker" function
            await context.CallActivityAsync(nameof(IotHubScaleWorker), null);

            // register a timer with the durable functions infrastructure to re-launch the orchestrator in the future
            DateTime wakeupTime = context.CurrentUtcDateTime.Add(TimeSpan.FromMinutes(JobFrequencyMinutes));
            await context.CreateTimer(wakeupTime, CancellationToken.None);

            log.Info(String.Format("IotHubScaleOrchestrator done...  tee'ing up next instance in {0} minutes.", JobFrequencyMinutes.ToString()));

            // end this 'instance' of the orchestrator and schedule another one to start based on the timer above
            context.ContinueAsNew(null);
        }
예제 #19
0
        public async Task <SendNotificationOrchestratorResult> Run(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger logger)
        {
            var input = context.GetInput <SendNotificationOrchestratorInput>();

            // Use Durable Entity to store orchestrator instanceId based on phonenumber
            var entityId = new EntityId(nameof(NotificationOrchestratorInstanceEntity), input.SupportContact.PhoneNumber);

            context.SignalEntity(
                entityId,
                nameof(NotificationOrchestratorInstanceEntity.Set),
                context.InstanceId);

            var activityInput = new SendNotificationActivityInput {
                Attempt     = input.NotificationAttemptCount,
                Message     = input.Message,
                PhoneNumber = input.SupportContact.PhoneNumber
            };
            await context.CallActivityAsync(
                nameof(SendNotificationActivity),
                activityInput);

            var waitTimeBetweenRetry = TimeSpan.FromSeconds(input.WaitTimeForEscalationInSeconds / input.MaxNotificationAttempts);

            // Orchestrator will wait until the event is received or waitTimeBetweenRetry is passed, defaults to false.
            var callBackResult = await context.WaitForExternalEvent <bool>(EventNames.Callback, waitTimeBetweenRetry, false);

            if (!callBackResult && input.NotificationAttemptCount < input.MaxNotificationAttempts)
            {
                // Call has not been answered, let's try again!
                input.NotificationAttemptCount++;
                context.ContinueAsNew(input);
            }

            // Call has been answered or MaxNotificationAttempts has been reached.
            var result = new SendNotificationOrchestratorResult {
                Attempt          = input.NotificationAttemptCount,
                PhoneNumber      = input.SupportContact.PhoneNumber,
                CallbackReceived = callBackResult
            };

            return(result);
        }
예제 #20
0
        public static async Task PeriodicCrawlExecuter(
            [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger logger)
        {
            logger = context.CreateReplaySafeLogger(logger);

            var dueTime = context.CurrentUtcDateTime.AddMinutes(15);

            dueTime = dueTime.AddSeconds(-dueTime.Second);

            var needCrawlContests = context.GetInput <List <string> >() ?? new List <string>();
            var tasks             = new Task <bool> [needCrawlContests.Count];

            logger.LogInformation($"needCrawlContests : [{string.Join(", ", needCrawlContests)}]");

            for (int i = 0; i < tasks.Length; i++)
            {
                logger.LogInformation($"start updating {needCrawlContests[i]}");
                tasks[i] = context.CallActivityAsync <bool>("UpdateAPerfs", needCrawlContests[i]);
            }
            for (int i = 0; i < tasks.Length; i++)
            {
                await tasks[i];
            }
            logger.LogInformation("completed");

            for (int i = tasks.Length - 1; i >= 0; i--)
            {
                if (!tasks[i].Result)
                {
                    needCrawlContests.RemoveAt(i);
                }
            }

            if (needCrawlContests.Count == 0)
            {
                return;
            }

            await context.CreateTimer(dueTime, CancellationToken.None);

            context.ContinueAsNew(needCrawlContests);
        }
예제 #21
0
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context)
        {
            await context.CallActivityAsync("EternalOrchestration_SayHello", "Sergio");

            var fireAt = context.CurrentUtcDateTime.AddSeconds(5);

            await context.CreateTimer(fireAt, CancellationToken.None);

            context.ContinueAsNew(null);

            //if ((context.CurrentUtcDateTime - _beginAt).TotalSeconds < 60)
            //{
            //    context.ContinueAsNew(null);
            //}
            //else
            //{
            //    context.SetOutput("The end.");
            //}
        }
        public static async Task RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log)
        {
            log.LogInformation($"Started orchestrator with ID {context.InstanceId}");
            var retryPolicy = new RetryOptions(new TimeSpan(0, 0, 0, 1), 10);

            retryPolicy.BackoffCoefficient = 2;

            var learners = await context.CallActivityAsync <List <Learner> >("GetLearners", null);

            if (learners.Count > 0)
            {
                log.LogInformation($"{learners.Count} learners to be processed");
                var learnerTasks = new List <Task>();
                foreach (var learner in learners)
                {
                    log.LogInformation($"Creating request to calculate payments for ULN: {learner.Uln} - LegalEntity {learner.LegalEntityId}");
                    Task task = context.CallActivityWithRetryAsync("CalculatePaymentsForLearner", retryPolicy, learner);
                    learnerTasks.Add(task);
                }

                log.LogInformation($"{learnerTasks.Count} tasks created");
                await Task.WhenAll(learnerTasks);

                context.ContinueAsNew(null);
                return;
            }

            log.LogInformation("All payment calculations complete");

            var parallelTasks = new List <Task>();

            var legalEntities = await context.CallActivityAsync <List <long> >("GetLegalEntities", null);

            foreach (var legalEntity in legalEntities)
            {
                Task task = context.CallActivityWithRetryAsync("PayLegalEntity", retryPolicy, legalEntity);
                parallelTasks.Add(task);
            }

            await Task.WhenAll(parallelTasks);
        }
        public static async Task <int> Orchestrator_EternalFunc(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            Counter counter = context.GetInput <Counter>();

            await context.CallActivityAsync(nameof(Activity_EternalFunc), counter.Value);

            DateTime timeoutAt = context.CurrentUtcDateTime.AddSeconds(counter.Value * 5);

            await context.CreateTimer(timeoutAt, CancellationToken.None);

            if (++counter.Value < 5)
            {
                context.ContinueAsNew(counter);
            }
            else
            {
                log.LogInformation("EternalFunc is stopped.");
            }

            return(counter.Value);
        }
예제 #24
0
        public static async Task StartTimeoutAsync([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            var entityId = ctx.InstanceId;

            using (var timeout = new CancellationTokenSource())
            {
                DateTime dueTime        = ctx.CurrentUtcDateTime.AddMinutes(30);
                Task     durableTimeout = ctx.CreateTimer(dueTime, timeout.Token);

                Task cancelEvent = ctx.WaitForExternalEvent("TimeoutReset");
                if (cancelEvent == await Task.WhenAny(cancelEvent, durableTimeout))
                {
                    timeout.Cancel();
                    ctx.ContinueAsNew(entityId);
                }
                else
                {
                    var proxy = ctx.CreateEntityProxy <ICartActions>(entityId);

                    proxy.Delete();
                }
            }
        }
예제 #25
0
        public async Task EnqAnswerOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            // アンケート回答をまとめるリスト(再帰呼び出し時は引数から受け取る)
            var list = context.GetInput <List <string> >() ?? new List <string>();

            // 「answer」という名前のイベントが起きるまで待機
            // 発生後、その結果を value に受け取る
            var value = await context.WaitForExternalEvent <(int index, string message, string replyToken)>("answer");

            log.LogInformation($"EnqAnswerOrchestrator - index: {value.index}");

            // リストに回答を追加
            list.Add(value.message);

            // インデックスが -1 なら終了とみなす
            if (value.index == -1)
            {
                // 完成したリストをリプライトークンとともに確認返信アクティビティに渡す
                await context.CallActivityAsync(nameof(SendSummaryActivity), (value.replyToken, list));
            }
            else
            {
                // 回答インデックスを更新
                context.SetCustomStatus(value.index);

                // 質問返信アクティビティ呼び出し
                // あえてオーケストレーターの最後で遠回しに返信処理を呼ぶのは、
                // インデックス更新前に返信されて同じ質問が返るのを防ぐため。
                // 返信などもアクティビティに任せないとおかしくなる(オーケストレーターは冪等性を維持)
                await context.CallActivityAsync(nameof(SendQuestionActivity), (value.replyToken, value.index + 1));

                // オーケストレーターを再帰的に呼び出す
                context.ContinueAsNew(list);
            }
        }
예제 #26
0
        public static async Task <string> ContinueAsNewMultipleTimersAndEvents([OrchestrationTrigger] IDurableOrchestrationContext ctx)
        {
            var input = ctx.GetInput <int>();

            if (input > 0)
            {
                var cts       = new CancellationTokenSource();
                var timerTask = ctx.CreateTimer <object>(ctx.CurrentUtcDateTime + TimeSpan.FromDays(1), null, cts.Token);
                var eventTask = ctx.WaitForExternalEvent($"signal{input}");
                await Task.WhenAny(timerTask, eventTask);

                cts.Cancel();
                ctx.ContinueAsNew(input - 1);
                return(input.ToString());
            }
            else if (input == 0)
            {
                return("ok");
            }
            else
            {
                return("error");
            }
        }
        public static async Task ProjectCommandMonitoringOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            var notification = context.GetInput <ProjectCommandNotification>();

            await context
            .CreateTimer(context.CurrentUtcDateTime.AddSeconds(5), CancellationToken.None)
            .ConfigureAwait(true);

            var active = await context
                         .CallActivityAsync <bool>(nameof(ProjectCommandMonitoringActivity), notification)
                         .ConfigureAwait(true);

            if (active)
            {
                // monitored orchestration still active - keep monitoring
                context.ContinueAsNew(notification);
            }
        }
예제 #28
0
        public static async Task Run(
            [OrchestrationTrigger] IDurableOrchestrationContext ctx,
            ILogger log)
        {
            var data = ctx.GetInput <OrchestratorData>();

            if (!ctx.IsReplaying)
            {
                log.LogInformation("Orchestration interval {Interval}. Current listeners: {Listeners}", data.Interval, string.Join(", ", data.MusicListeners?.Select(l => l.UserId)));
            }

            try
            {
                var           forceUpdateUsers = data.MusicListeners == null || data.Interval == 0;
                List <string> listeners;
                if (forceUpdateUsers)
                {
                    var users = await ctx.CallActivityAsync <IList <UserEntity> >(FunctionNames.GetAllUsersActivity, null);

                    listeners = users.Select(u => u.RowKey).ToList();
                }
                else
                {
                    listeners = GetListenersToUpdate(data.MusicListeners, ctx.CurrentUtcDateTime);
                }

                List <ListenerTrack> currentListenerTracks;
                if (listeners.Any())
                {
                    currentListenerTracks =
                        await ctx.CallActivityAsync <List <ListenerTrack> >(
                            FunctionNames.GetCurrentTracksActivity,
                            listeners
                            );
                }
                else
                {
                    currentListenerTracks = new List <ListenerTrack>();
                }

                await ctx.CallActivityAsync(
                    FunctionNames.SignalRTrackActivity,
                    currentListenerTracks
                    );

                if (data.MusicListeners == null)
                {
                    data.MusicListeners = new List <MusicListener>();
                }

                foreach (var playingTrack in currentListenerTracks.Where(t => t.currentTrack?.is_playing == true))
                {
                    var listener = data.MusicListeners.FirstOrDefault(m => m.UserId == playingTrack.userId);
                    if (listener != null)
                    {
                        listener.LastSeenActivity = ctx.CurrentUtcDateTime;
                    }
                    else
                    {
                        data.MusicListeners.Add(new MusicListener {
                            UserId = playingTrack.userId, LastSeenActivity = ctx.CurrentUtcDateTime
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                if (!ctx.IsReplaying)
                {
                    log.LogError(ex, "Failure while retrieving or signalling tracks.");
                }
            }

            DateTime nextIntervalTime;

            if (data.LastActivity > ctx.CurrentUtcDateTime.AddMinutes(-5))
            {
                nextIntervalTime = ctx.CurrentUtcDateTime.AddSeconds(Config.ActiveListenerIntervalSeconds);
            }
            else
            {
                nextIntervalTime = ctx.CurrentUtcDateTime.AddSeconds(Config.InactiveListenerIntervalSeconds);
            }

            using (var timeoutCts = new CancellationTokenSource())
            {
                Task durableTimeout = ctx.CreateTimer(nextIntervalTime, timeoutCts.Token);

                Task <bool> wakeUpEvent = ctx.WaitForExternalEvent <bool>(FunctionEvents.WakeUpOrchestrator);

                var winner = await Task.WhenAny(wakeUpEvent, durableTimeout);

                if (winner == wakeUpEvent)
                {
                    timeoutCts.Cancel();
                }
            }

            if (data.Interval > 2)
            {
                data.Interval = 0;
            }
            else
            {
                data.Interval = data.Interval + 1;
            }

            ctx.ContinueAsNew(data);
        }
        public async Task StartOrchestratorScheduler(
            [OrchestrationTrigger]
            IDurableOrchestrationContext context,
            ILogger log)
        {
            var taskItem = context.GetInput <TaskItem>();

            if (taskItem == null)
            {
                var error = new ProcessResult {
                    Sucess = false, Information = "Error getting task information"
                };
                AddLog(log, error);
                return;
            }
            TaskTypeEnum taskType = (TaskTypeEnum)taskItem.TaskType;

            string prepare  = ActivityFunctionPrepare(taskType);
            string process  = ActivityFunctionProcess(taskType);
            string complete = ActivityFunctionComplete(taskType);


            double secondInAFullDay = 86400;



            //// hvordan tjekker vi at task'en ikke allerde er scheduleret ?
            //// i så fald skal den terminineres.

            var      date            = context.CurrentUtcDateTime.Hour > taskItem.MonitorHour ? context.CurrentUtcDateTime.AddDays(1) : context.CurrentUtcDateTime;
            var      nextTime        = new DateTime(date.Year, date.Month, date.Day, taskItem.MonitorHour, 0, 0);
            var      pollingInterval = nextTime.Subtract(context.CurrentUtcDateTime).TotalSeconds;
            DateTime expiryTime      = new DateTime(3000, 1, 1);

            while (context.CurrentUtcDateTime < expiryTime)
            {
                // Orchestration sleeps until this time.
                var nextCheck = context.CurrentUtcDateTime.AddSeconds(pollingInterval);
                await context.CreateTimer(nextCheck, CancellationToken.None);

                var resultPrepare = await context.CallActivityAsync <ProcessResult>(prepare, taskItem.CustomerId);

                AddLog(log, resultPrepare);

                if (resultPrepare.Sucess)
                {
                    var resultProcess = await context.CallActivityAsync <ProcessResult>(process, taskItem.CustomerId);

                    AddLog(log, resultProcess);

                    if (resultProcess.Sucess)
                    {
                        var resultComplete = await context.CallActivityAsync <ProcessResult>(complete, taskItem.CustomerId);

                        AddLog(log, resultComplete);
                    }
                }
                // her sikres at denne uendelig løkke, ikke medfører at durable storage account fyldes op.
                context.ContinueAsNew(null); // her har man mulighed for at have informationer til næste genneløb
                pollingInterval = secondInAFullDay;
            }
        }
예제 #30
0
        public static async Task <string> MainOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            DateTime startTime = context.CurrentUtcDateTime;

            if (!context.IsReplaying)
            {
                log.LogInformation($"Main orchestrator (v{AzTwitterSarVersion.get()}), start time {startTime}. Call activity: GetTweets");
            }

            string lastTweetId = context.GetInput <string>();

            // 1) Get tweets from Twitter API
            List <TweetProcessingData> tweetData = await context.CallActivityAsync <List <TweetProcessingData> >(
                "A_GetTweets", lastTweetId);

            // The most likely case is that there are NO new tweets, so we provide
            // the short circuit which skips all the processing in this block, and
            // thus avoids a lot of replaying by the durable function mechanism.
            if (tweetData.Count > 0)
            {
                if (!context.IsReplaying)
                {
                    log.LogInformation($"Got {tweetData.Count} new tweets; enter processing sub-orchestration.");
                }

                // 2) Process tweets one by one to find interesting ones.
                var parallelScoringTasks = new List <Task <TweetProcessingData> >();
                foreach (var tpd in tweetData) // processes in order
                {
                    if (!context.IsReplaying)
                    {
                        log.LogInformation($"Call sub-orchestration: P_ProcessTweet for tweet: {tpd.IdStr}");
                    }
                    Task <TweetProcessingData> processTask = context.CallSubOrchestratorAsync <TweetProcessingData>(
                        "P_ProcessTweet", tpd);
                    parallelScoringTasks.Add(processTask);
                }
                await Task.WhenAll(parallelScoringTasks);

                // Sort the list of analyzed tweets by ascending id (chronologically).
                List <TweetProcessingData> logList = (from pt in parallelScoringTasks
                                                      orderby Int64.Parse(pt.Result.IdStr)
                                                      select pt.Result).ToList();

                // Find the tweets that shall be published, chronological order.
                List <TweetProcessingData> publishList = (
                    from tpd in logList
                    where tpd.ShallBePublished
                    orderby Int64.Parse(tpd.IdStr)
                    select tpd).ToList();

                // Parallel section for postprocessing tasks.
                {
                    if (!context.IsReplaying)
                    {
                        log.LogInformation($"Publishing {publishList.Count} tweets; logging {logList.Count} tweets.");
                    }

                    List <Task <int> > parallelPostprocessingTasks = new List <Task <int> >();
                    // We know there is something in the log list, but publishing we
                    // trigger only if there is something to do for this activity.
                    if (publishList.Count > 0)
                    {
                        parallelPostprocessingTasks.Add(context.CallActivityAsync <int>("A_PublishTweets", publishList));
                    }
                    parallelPostprocessingTasks.Add(context.CallActivityAsync <int>("A_LogTweets", logList));
                    await Task.WhenAll(parallelPostprocessingTasks);
                }

                // We know there has been >= 1 tweet, so we update the last seen id,
                // which is passed to the next call.
                lastTweetId = logList[logList.Count - 1].IdStr;
            }
            else
            {
                if (!context.IsReplaying)
                {
                    log.LogInformation($"Got no new tweets.");
                }
            }

            DateTime currentTime  = context.CurrentUtcDateTime;
            int      delaySeconds = GetDelaySeconds(context, log, startTime, currentTime);

            if (!context.IsReplaying)
            {
                log.LogInformation($"Determined delay: {delaySeconds} seconds after current time {currentTime}.");
            }

            if (delaySeconds > 0)
            {
                DateTime nextTime = currentTime.AddSeconds(delaySeconds);
                if (!context.IsReplaying)
                {
                    log.LogInformation($"Setting wakeup time: {nextTime}.");
                }
                await context.CreateTimer(nextTime, CancellationToken.None);

                context.ContinueAsNew(lastTweetId);
            }

            return(lastTweetId);
        }