public static async Task CallSendToConsumerActivityAsync(DurableOrchestrationContext ctx,
                                                          Microsoft.Azure.WebJobs.RetryOptions retryOptions, ConsumerData consumerData)
 {
     try
     {
         await ctx.CallActivityWithRetryAsync(nameof(SendToConsumerFunc), retryOptions, consumerData);
     }
     catch
     {
         //TODO: TEMPORARILY MARK THE CONSUMER AS BANNED IN CONSUMER_DB
     }
 }
        public static async Task OrchestrateConsumersFunc([OrchestrationTrigger] DurableOrchestrationContext ctx)
        {
            var changedProductIds = ctx.GetInput <List <CosmosDbIdentity> >();

            var retryOptions = new Microsoft.Azure.WebJobs.RetryOptions(firstRetryInterval: TimeSpan.FromSeconds(5),
                                                                        maxNumberOfAttempts: 3);

            var consumers = Environment.GetEnvironmentVariable("CONSUMERS", EnvironmentVariableTarget.Process)
                            ?.Split('|');

            var parallelTasks = consumers.Select(x => CallSendToConsumerActivityAsync(ctx, retryOptions,
                                                                                      new ConsumerData {
                ConsumerUrl = x, ChangedProducts = changedProductIds
            }));

            await Task.WhenAll(parallelTasks);
        }
 /// <summary>
 /// Schedules an orchestrator function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <typeparam name="TResult">The return type of the scheduled orchestrator function.</typeparam>
 /// <param name="functionName">The name of the orchestrator function to call.</param>
 /// <param name="retryOptions">The retry option for the orchestrator function.</param>
 /// <param name="instanceId">A unique ID to use for the sub-orchestration instance.</param>
 /// <param name="input">The JSON-serializeable input to pass to the orchestrator function.</param>
 /// <returns>A durable task that completes when the called orchestrator function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public abstract Task <TResult> CallSubOrchestratorWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, string instanceId, object input);
 /// <summary>
 /// Schedules an orchestrator function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <typeparam name="TResult">The return type of the scheduled orchestrator function.</typeparam>
 /// <param name="functionName">The name of the orchestrator function to call.</param>
 /// <param name="retryOptions">The retry option for the orchestrator function.</param>
 /// <param name="input">The JSON-serializeable input to pass to the orchestrator function.</param>
 /// <returns>A durable task that completes when the called orchestrator function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public virtual Task <TResult> CallSubOrchestratorWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, object input)
 {
     return(this.CallSubOrchestratorWithRetryAsync <TResult>(functionName, retryOptions, null, input));
 }
 /// <summary>
 /// Schedules an orchestrator function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <param name="functionName">The name of the orchestrator function to call.</param>
 /// <param name="retryOptions">The retry option for the orchestrator function.</param>
 /// <param name="instanceId">A unique ID to use for the sub-orchestration instance.</param>
 /// <param name="input">The JSON-serializeable input to pass to the orchestrator function.</param>
 /// <returns>A durable task that completes when the called orchestrator function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public virtual Task CallSubOrchestratorWithRetryAsync(string functionName, RetryOptions retryOptions, string instanceId, object input)
 {
     return(this.CallSubOrchestratorWithRetryAsync <object>(functionName, retryOptions, instanceId, input));
 }
 /// <summary>
 /// Schedules an activity function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <typeparam name="TResult">The return type of the scheduled activity function.</typeparam>
 /// <param name="functionName">The name of the activity function to call.</param>
 /// <param name="retryOptions">The retry option for the activity function.</param>
 /// <param name="input">The JSON-serializeable input to pass to the activity function.</param>
 /// <returns>A durable task that completes when the called activity function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public abstract Task <TResult> CallActivityWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, object input);
 /// <summary>
 /// Schedules an activity function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <param name="functionName">The name of the activity function to call.</param>
 /// <param name="retryOptions">The retry option for the activity function.</param>
 /// <param name="input">The JSON-serializeable input to pass to the activity function.</param>
 /// <returns>A durable task that completes when the called activity function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public virtual Task CallActivityWithRetryAsync(string functionName, RetryOptions retryOptions, object input)
 {
     return(this.CallActivityWithRetryAsync <object>(functionName, retryOptions, input));
 }
        private async Task <TResult> CallDurableTaskFunctionAsync <TResult>(
            string functionName,
            FunctionType functionType,
            string instanceId,
            RetryOptions retryOptions,
            object input)
        {
            this.ThrowIfInvalidAccess();

            // TODO: Support for versioning
            string version = DefaultVersion;

            this.config.ThrowIfFunctionDoesNotExist(functionName, functionType);

            Task <TResult> callTask;

            switch (functionType)
            {
            case FunctionType.Activity:
                System.Diagnostics.Debug.Assert(instanceId == null, "The instanceId parameter should not be used for activity functions.");
                if (retryOptions == null)
                {
                    callTask = this.innerContext.ScheduleTask <TResult>(functionName, version, input);
                }
                else
                {
                    callTask = this.innerContext.ScheduleWithRetry <TResult>(
                        functionName,
                        version,
                        retryOptions.GetRetryOptions(),
                        input);
                }

                break;

            case FunctionType.Orchestrator:
                if (retryOptions == null)
                {
                    callTask = this.innerContext.CreateSubOrchestrationInstance <TResult>(
                        functionName,
                        version,
                        instanceId,
                        input);
                }
                else
                {
                    callTask = this.innerContext.CreateSubOrchestrationInstanceWithRetry <TResult>(
                        functionName,
                        version,
                        instanceId,
                        retryOptions.GetRetryOptions(),
                        input);
                }

                break;

            default:
                throw new InvalidOperationException($"Unexpected function type '{functionType}'.");
            }

            string sourceFunctionId = this.orchestrationName;

            this.config.TraceHelper.FunctionScheduled(
                this.config.Options.HubName,
                functionName,
                this.InstanceId,
                reason: sourceFunctionId,
                functionType: functionType,
                isReplay: this.innerContext.IsReplaying);

            TResult   output;
            Exception exception = null;

            try
            {
                output = await callTask;
            }
            catch (TaskFailedException e)
            {
                exception = e;
                string message = string.Format(
                    "The {0} function '{1}' failed: \"{2}\". See the function execution logs for additional details.",
                    functionType.ToString().ToLowerInvariant(),
                    functionName,
                    e.InnerException?.Message);
                throw new FunctionFailedException(message, e.InnerException);
            }
            catch (SubOrchestrationFailedException e)
            {
                exception = e;
                string message = string.Format(
                    "The {0} function '{1}' failed: \"{2}\". See the function execution logs for additional details.",
                    functionType.ToString().ToLowerInvariant(),
                    functionName,
                    e.InnerException?.Message);
                throw new FunctionFailedException(message, e.InnerException);
            }
            catch (Exception e)
            {
                exception = e;
                throw;
            }
            finally
            {
                if (exception != null && this.innerContext.IsReplaying)
                {
                    // If this were not a replay, then the activity function trigger would have already
                    // emitted a FunctionFailed trace with the full exception details.
                    this.config.TraceHelper.FunctionFailed(
                        this.config.Options.HubName,
                        functionName,
                        this.InstanceId,
                        reason: $"(replayed {exception.GetType().Name})",
                        functionType: functionType,
                        isReplay: true);
                }
            }

            if (this.innerContext.IsReplaying)
            {
                // If this were not a replay, then the activity function trigger would have already
                // emitted a FunctionCompleted trace with the actual output details.
                this.config.TraceHelper.FunctionCompleted(
                    this.config.Options.HubName,
                    functionName,
                    this.InstanceId,
                    output: "(replayed)",
                    continuedAsNew: false,
                    functionType: functionType,
                    isReplay: true);
            }

            return(output);
        }
        /// <inheritdoc />
        public override Task <TResult> CallSubOrchestratorWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, string instanceId, object input)
        {
            if (retryOptions == null)
            {
                throw new ArgumentNullException(nameof(retryOptions));
            }

            return(this.CallDurableTaskFunctionAsync <TResult>(functionName, FunctionType.Orchestrator, instanceId, retryOptions, input));
        }
        /// <inheritdoc />
        public override Task <TResult> CallActivityWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, object input)
        {
            if (retryOptions == null)
            {
                throw new ArgumentNullException(nameof(retryOptions));
            }

            return(this.CallDurableTaskFunctionAsync <TResult>(functionName, FunctionType.Activity, null, retryOptions, input));
        }
Exemplo n.º 11
0
 /// <summary>
 /// Schedules an orchestrator function named <paramref name="functionName"/> for execution with retry options.
 /// </summary>
 /// <param name="functionName">The name of the orchestrator function to call.</param>
 /// <param name="retryOptions">The retry option for the orchestrator function.</param>
 /// <param name="input">The JSON-serializeable input to pass to the orchestrator function.</param>
 /// <returns>A durable task that completes when the called orchestrator function completes or fails.</returns>
 /// <exception cref="ArgumentNullException">
 /// The retry option object is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// The specified function does not exist, is disabled, or is not an orchestrator function.
 /// </exception>
 /// <exception cref="InvalidOperationException">
 /// The current thread is different than the thread which started the orchestrator execution.
 /// </exception>
 /// <exception cref="FunctionFailedException">
 /// The activity function failed with an unhandled exception.
 /// </exception>
 public Task CallSubOrchestratorWithRetryAsync(string functionName, RetryOptions retryOptions, object input)
 {
     return(this.CallSubOrchestratorWithRetryAsync <object>(functionName, retryOptions, null, input));
 }
Exemplo n.º 12
0
        private async Task <TResult> CallDurableTaskFunctionAsync <TResult>(string functionName,
                                                                            FunctionType functionType,
                                                                            RetryOptions retryOptions,
                                                                            object[] parameters)
        {
            this.ThrowIfInvalidAccess();

            // TODO: Support for versioning
            string version = DefaultVersion;

            this.config.ThrowIfInvalidFunctionType(functionName, functionType, version);

            Task <TResult> callTask;

            switch (functionType)
            {
            case FunctionType.Activity:
                if (retryOptions == null)
                {
                    callTask = this.innerContext.ScheduleTask <TResult>(functionName, version, parameters);
                }
                else
                {
                    callTask = this.innerContext.ScheduleWithRetry <TResult>(functionName, version,
                                                                             retryOptions.GetRetryOptions(), parameters);
                }
                break;

            case FunctionType.Orchestrator:
                if (retryOptions == null)
                {
                    callTask = this.innerContext.CreateSubOrchestrationInstance <TResult>(functionName, version,
                                                                                          JsonConvert.SerializeObject(parameters));
                }
                else
                {
                    callTask = this.innerContext.CreateSubOrchestrationInstanceWithRetry <TResult>(functionName, version,
                                                                                                   retryOptions.GetRetryOptions(), JsonConvert.SerializeObject(parameters));
                }
                break;

            default:
                throw new InvalidOperationException(
                          string.Format("Unexpected function type '{0}'.",
                                        functionType));
            }

            string sourceFunctionId = string.IsNullOrEmpty(this.orchestrationVersion)
                ? this.orchestrationName
                : this.orchestrationName + "/" + this.orchestrationVersion;

            this.config.TraceHelper.FunctionScheduled(
                this.config.HubName,
                functionName,
                version,
                this.InstanceId,
                reason: sourceFunctionId,
                functionType: functionType,
                isReplay: this.innerContext.IsReplaying);

            TResult output;

            try
            {
                output = await callTask;
            }
            catch (Exception e)
            {
                if (this.innerContext.IsReplaying)
                {
                    // If this were not a replay, then the activity function trigger would have already
                    // emitted a FunctionFailed trace with the full exception details.
                    this.config.TraceHelper.FunctionFailed(
                        this.config.HubName,
                        functionName,
                        version,
                        this.InstanceId,
                        reason: $"(replayed {e.GetType().Name})",
                        functionType: FunctionType.Activity,
                        isReplay: true);
                }
                throw;
            }

            if (this.innerContext.IsReplaying)
            {
                // If this were not a replay, then the activity function trigger would have already
                // emitted a FunctionCompleted trace with the actual output details.
                this.config.TraceHelper.FunctionCompleted(
                    this.config.HubName,
                    functionName,
                    version,
                    this.InstanceId,
                    output: "(replayed)",
                    continuedAsNew: false,
                    functionType: FunctionType.Activity,
                    isReplay: true);
            }

            return(output);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Schedules an orchestrator function named <paramref name="functionName"/> for execution with retry options.
        /// </summary>
        /// <typeparam name="TResult">The return type of the scheduled orchestrator function.</typeparam>
        /// <param name="functionName">The name of the orchestrator function to call.</param>
        /// <param name="retryOptions">The retry option for the orchestrator function.</param>
        /// <param name="parameters">The JSON-serializeable parameters to pass as input to the function.</param>
        /// <returns>A durable task that completes when the called function completes or fails.</returns>
        /// <exception cref="ArgumentNullException">
        /// The retry option object is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The specified function does not exist, is disabled, or is not an orchestrator function.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// The current thread is different than the thread which started the orchestrator execution.
        /// </exception>
        /// <exception cref="DurableTask.Core.Exceptions.TaskFailedException">
        /// The activity function failed with an unhandled exception.
        /// </exception>
        public async Task <TResult> CallSubOrchestratorWithRetryAsync <TResult>(string functionName, RetryOptions retryOptions, params object[] parameters)
        {
            if (retryOptions == null)
            {
                throw new ArgumentNullException(nameof(retryOptions));
            }

            return(await CallDurableTaskFunctionAsync <TResult>(functionName, FunctionType.Orchestrator, retryOptions, parameters));
        }