예제 #1
0
        public DurableTaskListener(
            DurableTaskExtension config,
            string functionId,
            FunctionName functionName,
            ITriggeredFunctionExecutor executor,
            FunctionType functionType,
            string storageConnectionString)
        {
            this.config   = config ?? throw new ArgumentNullException(nameof(config));
            this.executor = executor ?? throw new ArgumentNullException(nameof(executor));

            if (functionName == default(FunctionName))
            {
                throw new ArgumentNullException(nameof(functionName));
            }

            this.functionId              = functionId;
            this.functionName            = functionName;
            this.functionType            = functionType;
            this.storageConnectionString = storageConnectionString;
#if !FUNCTIONS_V1
            this.scaleMonitor = new Lazy <IScaleMonitor>(() =>
                                                         this.config.GetScaleMonitor(
                                                             this.functionId,
                                                             this.functionName,
                                                             this.storageConnectionString));
#endif
        }
예제 #2
0
        public Task <ITriggerBinding> TryCreateAsync(TriggerBindingProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ParameterInfo parameter = context.Parameter;
            OrchestrationTriggerAttribute trigger = parameter.GetCustomAttribute <OrchestrationTriggerAttribute>(inherit: false);

            if (trigger == null)
            {
                return(Task.FromResult <ITriggerBinding>(null));
            }

            // Priority for getting the name is [OrchestrationTrigger], [FunctionName], method name
            string name = trigger.Orchestration;

            if (string.IsNullOrEmpty(name))
            {
                MemberInfo method = context.Parameter.Member;
                name = method.GetCustomAttribute <FunctionNameAttribute>()?.Name ?? method.Name;
            }

            // The orchestration name defaults to the method name.
            var orchestratorName = new FunctionName(name);

            this.config.RegisterOrchestrator(orchestratorName, null);
            var binding = new OrchestrationTriggerBinding(this.config, parameter, orchestratorName);

            return(Task.FromResult <ITriggerBinding>(binding));
        }
 internal void RegisterOrchestrator(FunctionName orchestratorFunction, ITriggeredFunctionExecutor executor)
 {
     if (!this.registeredOrchestrators.TryAdd(orchestratorFunction, executor))
     {
         throw new ArgumentException($"The orchestrator function named '{orchestratorFunction}' is already registered.");
     }
 }
        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.History = orchestrationRuntimeState.Events;
            context.SetInput(orchestrationRuntimeState.Input);

            FunctionName orchestratorFunction = new FunctionName(context.Name);

            OrchestratorInfo info;

            if (!this.registeredOrchestrators.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 = 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.InstanceId,
                    context.IsReplaying);
            }

            await context.RunDeferredTasks();
        }
        public Task <ITriggerBinding> TryCreateAsync(TriggerBindingProviderContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ParameterInfo            parameter = context.Parameter;
            ActivityTriggerAttribute trigger   = parameter.GetCustomAttribute <ActivityTriggerAttribute>(inherit: false);

            if (trigger == null)
            {
                return(Task.FromResult <ITriggerBinding>(null));
            }

            // Priority for getting the name is [ActivityTrigger], [FunctionName], method name
            string name = trigger.Activity;

            if (string.IsNullOrEmpty(name))
            {
                MemberInfo method = context.Parameter.Member;
                name = method.GetCustomAttribute <FunctionNameAttribute>()?.Name ?? method.Name;
            }

            // The activity name defaults to the method name.
            var activityName = new FunctionName(name, trigger.Version);

            this.durableTaskConfig.RegisterActivity(activityName, null);
            var binding = new ActivityTriggerBinding(this, parameter, trigger, activityName);

            return(Task.FromResult <ITriggerBinding>(binding));
        }
 internal void RegisterActivity(FunctionName activityFunction, ITriggeredFunctionExecutor executor)
 {
     if (!this.registeredActivities.TryAdd(activityFunction, executor))
     {
         throw new ArgumentException($"The activity function named '{activityFunction}' is already registered.");
     }
 }
        internal OrchestratorInfo GetOrchestratorInfo(FunctionName orchestratorFunction)
        {
            OrchestratorInfo info;

            this.registeredOrchestrators.TryGetValue(orchestratorFunction, out info);

            return(info);
        }
예제 #8
0
        internal RegisteredFunctionInfo GetOrchestratorInfo(FunctionName orchestratorFunction)
        {
            RegisteredFunctionInfo info;

            this.knownOrchestrators.TryGetValue(orchestratorFunction, out info);

            return(info);
        }
예제 #9
0
 public OrchestrationTriggerBinding(
     DurableTaskExtension config,
     ParameterInfo parameterInfo,
     FunctionName orchestratorName)
 {
     this.config           = config;
     this.parameterInfo    = parameterInfo;
     this.orchestratorName = orchestratorName;
 }
 internal void RegisterActivity(FunctionName activityFunction, ITriggeredFunctionExecutor executor)
 {
     // Allow adding with a null key and subsequently updating with a non-null key.
     if (!this.registeredActivities.TryUpdate(activityFunction, executor, null))
     {
         if (!this.registeredActivities.TryAdd(activityFunction, executor))
         {
             throw new ArgumentException($"The activity function named '{activityFunction}' is already registered.");
         }
     }
 }
 public ActivityTriggerBinding(
     ActivityTriggerAttributeBindingProvider parent,
     ParameterInfo parameterInfo,
     ActivityTriggerAttribute attribute,
     FunctionName activity)
 {
     this.parent        = parent;
     this.parameterInfo = parameterInfo;
     this.attribute     = attribute;
     this.activityName  = activity;
 }
 internal void AssertOrchestratorExists(string name, string version)
 {
     var functionName = new FunctionName(name, version);
     if (!this.registeredOrchestrators.ContainsKey(functionName))
     {
         throw new ArgumentException(
             string.Format("The function '{0}' doesn't exist, is disabled, or is not an orchestrator function. The following are the active orchestrator functions: {1}.",
                 functionName,
                 string.Join(", ", this.registeredOrchestrators.Keys)));
     }
 }
        internal void DeregisterActivity(FunctionName activityFunction)
        {
            this.TraceHelper.ExtensionInformationalEvent(
                this.Options.HubName,
                instanceId: string.Empty,
                functionName: activityFunction.Name,
                message: $"Deregistering orchestrator function named {activityFunction}.",
                writeToUserLogs: false);

            this.registeredActivities.TryRemove(activityFunction, out _);
        }
 internal void RegisterOrchestrator(FunctionName orchestratorFunction, OrchestratorInfo orchestratorInfo)
 {
     if (!this.registeredOrchestrators.TryUpdate(orchestratorFunction, orchestratorInfo, null))
     {
         if (!this.registeredOrchestrators.TryAdd(orchestratorFunction, orchestratorInfo))
         {
             throw new ArgumentException(
                       $"The orchestrator function named '{orchestratorFunction}' is already registered.");
         }
     }
 }
        TaskActivity INameVersionObjectManager<TaskActivity>.GetObject(string name, string version)
        {
            FunctionName activityFunction = new FunctionName(name, version);

            ITriggeredFunctionExecutor executor;
            if (!this.registeredActivities.TryGetValue(activityFunction, out executor))
            {
                throw new InvalidOperationException($"Activity function '{activityFunction}' does not exist.");
            }

            return new TaskActivityShim(this, executor, name, version);
        }
 public OrchestrationTriggerBinding(
     DurableTaskExtension config,
     ParameterInfo parameterInfo,
     FunctionName orchestratorName,
     string storageConnectionString)
 {
     this.config                  = config;
     this.parameterInfo           = parameterInfo;
     this.orchestratorName        = orchestratorName;
     this.storageConnectionString = storageConnectionString;
     this.BindingDataContract     = GetBindingDataContract(parameterInfo);
 }
예제 #17
0
 public EntityTriggerBinding(
     DurableTaskExtension config,
     ParameterInfo parameterInfo,
     FunctionName entityName,
     string storageConnectionString)
 {
     this.config                  = config;
     this.parameterInfo           = parameterInfo;
     this.entityName              = entityName;
     this.storageConnectionString = storageConnectionString;
     this.BindingDataContract     = GetBindingDataContract(parameterInfo);
 }
예제 #18
0
        internal void ThrowIfFunctionDoesNotExist(string name, FunctionType functionType)
        {
            var functionName = new FunctionName(name);

            if (functionType == FunctionType.Activity && !this.knownActivities.ContainsKey(functionName))
            {
                throw new ArgumentException(this.GetInvalidActivityFunctionMessage(name));
            }
            else if (functionType == FunctionType.Orchestrator && !this.knownOrchestrators.ContainsKey(functionName))
            {
                throw new ArgumentException(this.GetInvalidOrchestratorFunctionMessage(name));
            }
        }
예제 #19
0
 public ActivityTriggerBinding(
     ActivityTriggerAttributeBindingProvider parent,
     ParameterInfo parameterInfo,
     ActivityTriggerAttribute attribute,
     FunctionName activity,
     DurableTaskExtension durableTaskConfig)
 {
     this.parent            = parent;
     this.parameterInfo     = parameterInfo;
     this.attribute         = attribute;
     this.activityName      = activity;
     this.contract          = GetBindingDataContract(parameterInfo);
     this.durableTaskConfig = durableTaskConfig;
 }
예제 #20
0
        internal void DeregisterEntity(FunctionName entityFunction)
        {
            RegisteredFunctionInfo existing;

            if (this.knownOrchestrators.TryGetValue(entityFunction, out existing) && !existing.IsDeregistered)
            {
                existing.IsDeregistered = true;

                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: entityFunction.Name,
                    message: $"Deregistered entity function named {entityFunction}.",
                    writeToUserLogs: false);
            }
        }
 public DurableTaskScaleMonitor(
     string functionId,
     FunctionName functionName,
     string hubName,
     string storageConnectionString,
     EndToEndTraceHelper traceHelper,
     DisconnectedPerformanceMonitor performanceMonitor = null)
 {
     this.functionId              = functionId;
     this.functionName            = functionName;
     this.hubName                 = hubName;
     this.storageConnectionString = storageConnectionString;
     this.performanceMonitor      = performanceMonitor;
     this.traceHelper             = traceHelper;
     this.scaleMonitorDescriptor  = new ScaleMonitorDescriptor($"{this.functionId}-DurableTaskTrigger-{this.hubName}".ToLower());
 }
예제 #22
0
        internal void DeregisterActivity(FunctionName activityFunction)
        {
            RegisteredFunctionInfo info;

            if (this.knownActivities.TryGetValue(activityFunction, out info) && !info.IsDeregistered)
            {
                info.IsDeregistered = true;

                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: activityFunction.Name,
                    message: $"Deregistered activity function named {activityFunction}.",
                    writeToUserLogs: false);
            }
        }
예제 #23
0
        public DurableTaskListener(
            DurableTaskExtension config,
            FunctionName functionName,
            ITriggeredFunctionExecutor executor,
            bool isOrchestrator)
        {
            this.config   = config ?? throw new ArgumentNullException(nameof(config));
            this.executor = executor ?? throw new ArgumentNullException(nameof(executor));

            if (functionName == default(FunctionName))
            {
                throw new ArgumentNullException(nameof(functionName));
            }

            this.functionName   = functionName;
            this.isOrchestrator = isOrchestrator;
        }
        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);
            }

            await context.RunDeferredTasks();
        }
        internal void RegisterActivity(FunctionName activityFunction, ITriggeredFunctionExecutor executor)
        {
            // Allow adding with a null key and subsequently updating with a non-null key.
            if (!this.registeredActivities.TryUpdate(activityFunction, executor, null))
            {
                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: activityFunction.Name,
                    message: $"Registering orchestrator function named {activityFunction}.",
                    writeToUserLogs: false);

                if (!this.registeredActivities.TryAdd(activityFunction, executor))
                {
                    throw new ArgumentException($"The activity function named '{activityFunction}' is already registered.");
                }
            }
        }
        internal void RegisterOrchestrator(FunctionName orchestratorFunction, OrchestratorInfo orchestratorInfo)
        {
            if (!this.registeredOrchestrators.TryUpdate(orchestratorFunction, orchestratorInfo, null))
            {
                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: orchestratorFunction.Name,
                    message: $"Registering orchestrator function named {orchestratorFunction}.",
                    writeToUserLogs: false);

                if (!this.registeredOrchestrators.TryAdd(orchestratorFunction, orchestratorInfo))
                {
                    throw new ArgumentException(
                              $"The orchestrator function named '{orchestratorFunction}' is already registered.");
                }
            }
        }
예제 #27
0
        /// <summary>
        /// Called by the Durable Task Framework: Returns the specified <see cref="TaskActivity"/>.
        /// </summary>
        /// <param name="name">The name of the activity to return.</param>
        /// <param name="version">Not used.</param>
        /// <returns>An activity shim that delegates execution to an activity function.</returns>
        TaskActivity INameVersionObjectManager <TaskActivity> .GetObject(string name, string version)
        {
            FunctionName activityFunction = new FunctionName(name);

            RegisteredFunctionInfo info;

            if (!this.knownActivities.TryGetValue(activityFunction, out info))
            {
                string message = $"Activity function '{activityFunction}' does not exist.";
                this.TraceHelper.ExtensionWarningEvent(
                    this.Options.HubName,
                    activityFunction.Name,
                    string.Empty /* TODO: Flow the instance id into this event */,
                    message);
                throw new InvalidOperationException(message);
            }

            return(new TaskActivityShim(this, info.Executor, name));
        }
예제 #28
0
        internal void RegisterActivity(FunctionName activityFunction, ITriggeredFunctionExecutor executor)
        {
            if (this.knownActivities.TryGetValue(activityFunction, out RegisteredFunctionInfo existing))
            {
                existing.Executor = executor;
            }
            else
            {
                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: activityFunction.Name,
                    message: $"Registering activity function named {activityFunction}.",
                    writeToUserLogs: false);

                var info = new RegisteredFunctionInfo(executor, isOutOfProc: false);
                this.knownActivities[activityFunction] = info;
            }
        }
예제 #29
0
        internal void RegisterOrchestrator(FunctionName orchestratorFunction, RegisteredFunctionInfo orchestratorInfo)
        {
            if (orchestratorInfo != null)
            {
                orchestratorInfo.IsDeregistered = false;
            }

            if (this.knownOrchestrators.TryAdd(orchestratorFunction, orchestratorInfo))
            {
                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: orchestratorFunction.Name,
                    message: $"Registered orchestrator function named {orchestratorFunction}.",
                    writeToUserLogs: false);
            }
            else
            {
                this.knownOrchestrators[orchestratorFunction] = orchestratorInfo;
            }
        }
예제 #30
0
        internal void RegisterEntity(FunctionName entityFunction, RegisteredFunctionInfo entityInfo)
        {
            if (entityInfo != null)
            {
                entityInfo.IsDeregistered = false;
            }

            if (this.knownEntities.TryAdd(entityFunction, entityInfo))
            {
                this.TraceHelper.ExtensionInformationalEvent(
                    this.Options.HubName,
                    instanceId: string.Empty,
                    functionName: entityFunction.Name,
                    message: $"Registered entity function named {entityFunction}.",
                    writeToUserLogs: false);
            }
            else
            {
                this.knownEntities[entityFunction] = entityInfo;
            }
        }