private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next) { TaskOrchestrationShim shim = (TaskOrchestrationShim)dispatchContext.GetProperty <TaskOrchestration>(); DurableOrchestrationContext context = shim.Context; FunctionName orchestratorFunction = new FunctionName(context.Name, context.Version); ITriggeredFunctionExecutor executor; if (!this.registeredOrchestrators.TryGetValue(orchestratorFunction, out executor)) { throw new InvalidOperationException($"Orchestrator function '{orchestratorFunction}' does not exist."); } // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking). FunctionResult result = await executor.TryExecuteAsync( new TriggeredFunctionData { TriggerValue = context, #pragma warning disable CS0618 // Approved for use by this extension InvokeHandler = userCodeInvoker => { // 2. Configure the shim with the inner invoker to execute the user code. shim.SetFunctionInvocationCallback(userCodeInvoker); // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim. return(next()); }, #pragma warning restore CS0618 }, CancellationToken.None); if (!context.IsCompleted) { this.TraceHelper.FunctionAwaited( context.HubName, context.Name, context.Version, context.InstanceId, context.IsReplaying); } }
private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next) { TaskOrchestrationShim shim = (TaskOrchestrationShim)dispatchContext.GetProperty <TaskOrchestration>(); DurableOrchestrationContext context = shim.Context; string executorKey = GetFunctionKey(context.Name, context.Version); ITriggeredFunctionExecutor functionsPipelineInvoker; if (!orchestratorFunctionExecutors.TryGetValue(executorKey, out functionsPipelineInvoker)) { throw new ArgumentException($"No orchestration function named '{context.Name}' with version '{context.Version}' is registered."); } // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking). FunctionResult result = await functionsPipelineInvoker.TryExecuteAsync( new TriggeredFunctionData { TriggerValue = context, InvokeHandler = userCodeInvoker => { // 2. Configure the shim with the inner invoker to execute the user code. shim.SetFunctionInvocationCallback(userCodeInvoker); // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim. return(next()); } }, CancellationToken.None); if (!context.IsCompleted) { this.config.TraceHelper.FunctionAwaited( context.HubName, context.Name, context.Version, context.InstanceId, context.IsReplaying); } }
/// <summary> /// Called by the Durable Task Framework: Returns the specified <see cref="TaskOrchestration"/>. /// </summary> /// <param name="name">The name of the orchestration to return.</param> /// <param name="version">The version of the orchestration to return.</param> /// <returns>An orchestration shim that delegates execution to an orchestrator function.</returns> TaskOrchestration INameVersionObjectManager <TaskOrchestration> .GetObject(string name, string version) { var context = new DurableOrchestrationContext(this, name, version); return(new TaskOrchestrationShim(this, context)); }
private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next) { TaskOrchestrationShim shim = dispatchContext.GetProperty <TaskOrchestration>() as TaskOrchestrationShim; if (shim == null) { // This is not an orchestration - skip. await next(); return; } DurableOrchestrationContext context = (DurableOrchestrationContext)shim.Context; OrchestrationRuntimeState orchestrationRuntimeState = dispatchContext.GetProperty <OrchestrationRuntimeState>(); if (orchestrationRuntimeState.ParentInstance != null) { context.ParentInstanceId = orchestrationRuntimeState.ParentInstance.OrchestrationInstance.InstanceId; } context.InstanceId = orchestrationRuntimeState.OrchestrationInstance.InstanceId; context.ExecutionId = orchestrationRuntimeState.OrchestrationInstance.ExecutionId; context.IsReplaying = orchestrationRuntimeState.ExecutionStartedEvent.IsPlayed; context.History = orchestrationRuntimeState.Events; context.RawInput = orchestrationRuntimeState.Input; var info = shim.GetFunctionInfo(); if (info == null) { string message = this.GetInvalidOrchestratorFunctionMessage(context.FunctionName); this.TraceHelper.ExtensionWarningEvent( this.Options.HubName, orchestrationRuntimeState.Name, orchestrationRuntimeState.OrchestrationInstance.InstanceId, message); throw new InvalidOperationException(message); } // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking). FunctionResult result = await info.Executor.TryExecuteAsync( new TriggeredFunctionData { TriggerValue = context, #pragma warning disable CS0618 // Approved for use by this extension InvokeHandler = async userCodeInvoker => { // 2. Configure the shim with the inner invoker to execute the user code. shim.SetFunctionInvocationCallback(userCodeInvoker); // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim. await next(); // 4. If an activity failed, indicate to the functions Host that this execution failed via an exception if (context.IsCompleted && context.OrchestrationException != null) { context.OrchestrationException.Throw(); } }, #pragma warning restore CS0618 }, CancellationToken.None); if (!context.IsCompleted) { this.TraceHelper.FunctionAwaited( context.HubName, context.Name, FunctionType.Orchestrator, context.InstanceId, context.IsReplaying); } if (context.IsCompleted && context.PreserveUnprocessedEvents) { // Reschedule any unprocessed external events so that they can be picked up // in the next iteration. context.RescheduleBufferedExternalEvents(); } await context.RunDeferredTasks(); }
public LockReleaser(DurableOrchestrationContext context) { this.context = context; }
public TaskOrchestrationShim(DurableTaskExtension config, DurabilityProvider durabilityProvider, string name) : base(config) { this.context = new DurableOrchestrationContext(config, durabilityProvider, name); this.outOfProcShim = new OutOfProcOrchestrationShim(this.context); }
private async Task OrchestrationMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next) { TaskOrchestrationShim shim = (TaskOrchestrationShim)dispatchContext.GetProperty <TaskOrchestration>(); DurableOrchestrationContext context = shim.Context; OrchestrationRuntimeState orchestrationRuntimeState = dispatchContext.GetProperty <OrchestrationRuntimeState>(); if (orchestrationRuntimeState.ParentInstance != null) { context.ParentInstanceId = orchestrationRuntimeState.ParentInstance.OrchestrationInstance.InstanceId; } context.InstanceId = orchestrationRuntimeState.OrchestrationInstance.InstanceId; context.IsReplaying = orchestrationRuntimeState.ExecutionStartedEvent.IsPlayed; context.History = orchestrationRuntimeState.Events; context.SetInput(orchestrationRuntimeState.Input); FunctionName orchestratorFunction = new FunctionName(context.Name); RegisteredFunctionInfo info; if (!this.knownOrchestrators.TryGetValue(orchestratorFunction, out info)) { string message = this.GetInvalidOrchestratorFunctionMessage(orchestratorFunction.Name); this.TraceHelper.ExtensionWarningEvent( this.Options.HubName, orchestratorFunction.Name, orchestrationRuntimeState.OrchestrationInstance.InstanceId, message); throw new InvalidOperationException(message); } // 1. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking). FunctionResult result = await info.Executor.TryExecuteAsync( new TriggeredFunctionData { TriggerValue = context, #pragma warning disable CS0618 // Approved for use by this extension InvokeHandler = async userCodeInvoker => { // 2. Configure the shim with the inner invoker to execute the user code. shim.SetFunctionInvocationCallback(userCodeInvoker); // 3. Move to the next stage of the DTFx pipeline to trigger the orchestrator shim. await next(); // 4. If an activity failed, indicate to the functions Host that this execution failed via an exception if (context.IsCompleted && context.OrchestrationException != null) { context.OrchestrationException.Throw(); } }, #pragma warning restore CS0618 }, CancellationToken.None); if (!context.IsCompleted) { this.TraceHelper.FunctionAwaited( context.HubName, context.Name, context.InstanceId, context.IsReplaying); } await context.RunDeferredTasks(); }
private async Task ProcessAsyncActions(AsyncAction[][] actions) { if (actions == null) { throw new ArgumentNullException("Out-of-proc orchestrator schema must have a non-null actions property."); } // Each actionSet represents a particular execution of the orchestration. foreach (AsyncAction[] actionSet in actions) { var tasks = new List <Task>(actions.Length); DurableOrchestrationContext ctx = this.context as DurableOrchestrationContext; // An actionSet represents all actions that were scheduled within that execution. foreach (AsyncAction action in actionSet) { switch (action.ActionType) { case AsyncActionType.CallActivity: tasks.Add(this.context.CallActivityAsync(action.FunctionName, action.Input)); break; case AsyncActionType.CreateTimer: using (var cts = new CancellationTokenSource()) { if (ctx != null) { ctx.ThrowIfInvalidTimerLengthForStorageProvider(action.FireAt); } tasks.Add(this.context.CreateTimer(action.FireAt, cts.Token)); if (action.IsCanceled) { cts.Cancel(); } } break; case AsyncActionType.CallActivityWithRetry: tasks.Add(this.context.CallActivityWithRetryAsync(action.FunctionName, action.RetryOptions, action.Input)); break; case AsyncActionType.CallSubOrchestrator: tasks.Add(this.context.CallSubOrchestratorAsync(action.FunctionName, action.InstanceId, action.Input)); break; case AsyncActionType.CallSubOrchestratorWithRetry: tasks.Add(this.context.CallSubOrchestratorWithRetryAsync(action.FunctionName, action.RetryOptions, action.InstanceId, action.Input)); break; case AsyncActionType.CallEntity: { var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); tasks.Add(this.context.CallEntityAsync(entityId, action.EntityOperation, action.Input)); break; } case AsyncActionType.SignalEntity: { // We do not add a task because this is 'fire and forget' var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); this.context.SignalEntity(entityId, action.EntityOperation, action.Input); break; } case AsyncActionType.ScheduledSignalEntity: { // We do not add a task because this is 'fire and forget' var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); this.context.SignalEntity(entityId, action.FireAt, action.EntityOperation, action.Input); break; } case AsyncActionType.ContinueAsNew: this.context.ContinueAsNew(action.Input); break; case AsyncActionType.WaitForExternalEvent: tasks.Add(this.context.WaitForExternalEvent <object>(action.ExternalEventName)); break; case AsyncActionType.CallHttp: tasks.Add(this.context.CallHttpAsync(action.HttpRequest)); break; default: break; } } if (tasks.Count > 0) { await Task.WhenAny(tasks); } } }
/// <summary> /// Invokes a DF API based on the input action object. /// </summary> /// <param name="action">An OOProc action object representing a DF task.</param> /// <returns>If the API returns a task, the DF task corresponding to the input action. Else, null.</returns> private Task InvokeAPIFromAction(AsyncAction action) { Task fireAndForgetTask = Task.CompletedTask; Task task = null; switch (action.ActionType) { case AsyncActionType.CallActivity: task = this.context.CallActivityAsync(action.FunctionName, action.Input); break; case AsyncActionType.CreateTimer: DurableOrchestrationContext ctx = this.context as DurableOrchestrationContext; using (var cts = new CancellationTokenSource()) { if (ctx != null) { ctx.ThrowIfInvalidTimerLengthForStorageProvider(action.FireAt); } task = this.context.CreateTimer(action.FireAt, cts.Token); if (action.IsCanceled) { cts.Cancel(); } } break; case AsyncActionType.CallActivityWithRetry: task = this.context.CallActivityWithRetryAsync(action.FunctionName, action.RetryOptions, action.Input); break; case AsyncActionType.CallSubOrchestrator: task = this.context.CallSubOrchestratorAsync(action.FunctionName, action.InstanceId, action.Input); break; case AsyncActionType.CallSubOrchestratorWithRetry: task = this.context.CallSubOrchestratorWithRetryAsync(action.FunctionName, action.RetryOptions, action.InstanceId, action.Input); break; case AsyncActionType.CallEntity: { var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); task = this.context.CallEntityAsync(entityId, action.EntityOperation, action.Input); break; } case AsyncActionType.SignalEntity: { // We do not add a task because this is 'fire and forget' var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); this.context.SignalEntity(entityId, action.EntityOperation, action.Input); task = fireAndForgetTask; break; } case AsyncActionType.ScheduledSignalEntity: { // We do not add a task because this is 'fire and forget' var entityId = EntityId.GetEntityIdFromSchedulerId(action.InstanceId); this.context.SignalEntity(entityId, action.FireAt, action.EntityOperation, action.Input); task = fireAndForgetTask; break; } case AsyncActionType.ContinueAsNew: this.context.ContinueAsNew(action.Input); task = fireAndForgetTask; break; case AsyncActionType.WaitForExternalEvent: task = this.context.WaitForExternalEvent <object>(action.ExternalEventName); break; case AsyncActionType.CallHttp: task = this.context.CallHttpAsync(action.HttpRequest); break; case AsyncActionType.WhenAll: task = Task.WhenAll(action.CompoundActions.Select(x => this.InvokeAPIFromAction(x))); break; case AsyncActionType.WhenAny: task = Task.WhenAny(action.CompoundActions.Select(x => this.InvokeAPIFromAction(x))); break; default: throw new Exception($"Received an unexpected action type from the out-of-proc function: '${action.ActionType}'."); } return(task); }
TaskOrchestration INameVersionObjectManager <TaskOrchestration> .GetObject(string name, string version) { var context = new DurableOrchestrationContext(this.config.HubName, name, version, this.config.TraceHelper); return(new TaskOrchestrationShim(this.config, context)); }