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)); }
/// <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)); }
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); }
/// <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)); }