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));
        }
Esempio n. 4
0
        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();
        }
Esempio n. 5
0
 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);
 }
Esempio n. 7
0
        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();
        }
Esempio n. 8
0
        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));
        }