public HttpApiHandler(DurableTaskExtension config, ILogger logger)
 {
     this.config = config;
     this.logger = logger;
 }
Пример #2
0
        public override async Task <string> Execute(OrchestrationContext innerContext, string serializedInput)
        {
            // Supress "Variable is assigned but its value is never used" in Functions V1
#pragma warning disable CS0219
            OrchestrationRuntimeStatus status; // for reporting the status of the orchestration on App Insights
#pragma warning restore CS0219

            if (this.FunctionInvocationCallback == null)
            {
                throw new InvalidOperationException($"The {nameof(this.FunctionInvocationCallback)} has not been assigned!");
            }

            if (!this.config.MessageDataConverter.IsDefault)
            {
                innerContext.MessageDataConverter = this.config.MessageDataConverter;
            }

            if (!this.config.ErrorDataConverter.IsDefault)
            {
                innerContext.ErrorDataConverter = this.config.ErrorDataConverter;
            }

            this.context.InnerContext = innerContext;
            this.context.RawInput     = serializedInput;

            this.Config.TraceHelper.FunctionStarting(
                this.context.HubName,
                this.context.Name,
                this.context.InstanceId,
                this.Config.GetIntputOutputTrace(serializedInput),
                FunctionType.Orchestrator,
                this.context.IsReplaying);
            status = OrchestrationRuntimeStatus.Running;
#if !FUNCTIONS_V1
            // On a replay, the orchestrator will either go into a 'Completed'
            // state or a 'Failed' state. We want to avoid tagging them as
            // 'Running' while replaying because this could result in
            // Application Insights reporting the wrong status.
            if (!innerContext.IsReplaying)
            {
                DurableTaskExtension.TagActivityWithOrchestrationStatus(status, this.context.InstanceId);
            }
#endif

            var orchestratorInfo = this.Config.GetOrchestratorInfo(new FunctionName(this.context.Name));

            if (!this.context.IsReplaying)
            {
                this.context.AddDeferredTask(() => this.Config.LifeCycleNotificationHelper.OrchestratorStartingAsync(
                                                 this.context.HubName,
                                                 this.context.Name,
                                                 this.context.InstanceId,
                                                 this.context.IsReplaying));
            }

            await this.InvokeUserCodeAndHandleResults(orchestratorInfo, innerContext);

            // release any locks that were held by the orchestration
            // just in case the application code did not do so already
            this.context.ReleaseLocks();

            string serializedOutput = this.context.GetSerializedOutput();

            this.Config.TraceHelper.FunctionCompleted(
                this.context.HubName,
                this.context.Name,
                this.context.InstanceId,
                this.Config.GetIntputOutputTrace(serializedOutput),
                this.context.ContinuedAsNew,
                FunctionType.Orchestrator,
                this.context.IsReplaying);
            status = OrchestrationRuntimeStatus.Completed;

            if (!this.context.IsReplaying)
            {
                this.context.AddDeferredTask(() => this.Config.LifeCycleNotificationHelper.OrchestratorCompletedAsync(
                                                 this.context.HubName,
                                                 this.context.Name,
                                                 this.context.InstanceId,
                                                 this.context.ContinuedAsNew,
                                                 this.context.IsReplaying));
            }
#if !FUNCTIONS_V1
            DurableTaskExtension.TagActivityWithOrchestrationStatus(status, this.context.InstanceId);
#endif
            return(serializedOutput);
        }
Пример #3
0
 internal DurableActivityContext(DurableTaskExtension config, string instanceId, string serializedInput)
 {
     this.messageDataConverter = config.MessageDataConverter;
     this.instanceId           = instanceId;
     this.serializedInput      = serializedInput;
 }
Пример #4
0
 public DurableEntityContext(DurableTaskExtension config, EntityId entity, TaskEntityShim shim)
     : base(config, entity.EntityName)
 {
     this.self = entity;
     this.shim = shim;
 }
Пример #5
0
        // Responsible for invoking the function, handling the exception, set the output, and if
        // the function execution is out-of-process, handles the replay.
        private async Task InvokeUserCodeAndHandleResults(
            RegisteredFunctionInfo orchestratorInfo,
            OrchestrationContext innerContext)
        {
            try
            {
                Task invokeTask = this.FunctionInvocationCallback();
                if (invokeTask is Task <object> resultTask)
                {
                    // Orchestrator threads cannot perform async I/O, so block on such out-of-proc threads.
                    // Possible performance implications; may need revisiting.
                    object returnValue = orchestratorInfo.IsOutOfProc ? resultTask.Result : await resultTask;
                    if (returnValue != null)
                    {
                        if (orchestratorInfo.IsOutOfProc)
                        {
                            await this.outOfProcShim.HandleDurableTaskReplay(new OrchestrationInvocationResult()
                            {
                                ReturnValue = returnValue,
                            });
                        }
                        else
                        {
                            this.context.SetOutput(returnValue);
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException("The WebJobs runtime returned a invocation task that does not support return values!");
                }
            }
            catch (Exception e)
            {
                if (orchestratorInfo.IsOutOfProc &&
                    OutOfProcExceptionHelpers.TryExtractOutOfProcStateJson(e.InnerException, out string returnValue) &&
                    !string.IsNullOrEmpty(returnValue))
                {
                    try
                    {
                        await this.outOfProcShim.HandleDurableTaskReplay(new OrchestrationInvocationResult()
                        {
                            ReturnValue = returnValue,
                            Exception   = e,
                        });
                    }
                    catch (OrchestrationFailureException ex)
                    {
                        this.TraceAndSendExceptionNotification(ex.Details);
                        this.context.OrchestrationException = ExceptionDispatchInfo.Capture(ex);
                        throw ex;
                    }
                }
                else
                {
                    this.TraceAndSendExceptionNotification(e.ToString());
                    var orchestrationException = new OrchestrationFailureException(
                        $"Orchestrator function '{this.context.Name}' failed: {e.Message}",
                        Utils.SerializeCause(e, innerContext.ErrorDataConverter));

                    this.context.OrchestrationException =
                        ExceptionDispatchInfo.Capture(orchestrationException);

#if !FUNCTIONS_V1
                    DurableTaskExtension.TagActivityWithOrchestrationStatus(OrchestrationRuntimeStatus.Failed, this.context.InstanceId);
#endif

                    throw orchestrationException;
                }
            }
            finally
            {
                this.context.IsCompleted = true;
            }
        }
Пример #6
0
 public BindingHelper(DurableTaskExtension config, EndToEndTraceHelper traceHelper)
 {
     this.config      = config;
     this.traceHelper = traceHelper;
 }
Пример #7
0
 public HttpApiHandler(DurableTaskExtension config, ILogger logger)
 {
     this.config        = config;
     this.dataConverter = this.config.DataConverter;
     this.logger        = logger;
 }
Пример #8
0
 internal DurableCommonContext(DurableTaskExtension config, string functionName)
 {
     this.Config       = config ?? throw new ArgumentNullException(nameof(config));
     this.FunctionName = functionName;
 }
Пример #9
0
 internal DurableCommonContext(DurableTaskExtension config, string functionName)
 {
     this.Config       = config ?? throw new ArgumentNullException(nameof(config));
     this.FunctionName = functionName;
     this.EntityMessageReorderWindow = TimeSpan.FromMinutes(config.Options.EntityMessageReorderWindowInMinutes);
 }
        public override async Task <string> Execute(OrchestrationContext innerContext, string serializedInput)
        {
#if !FUNCTIONS_V1
            // Adding "Tags" to activity allows using App Insights to query current state of entities
            var activity = Activity.Current;
            OrchestrationRuntimeStatus status = OrchestrationRuntimeStatus.Running;

            DurableTaskExtension.TagActivityWithOrchestrationStatus(status, this.context.InstanceId, true);
#endif

            if (this.operationBatch.Count == 0 &&
                this.lockRequest == null &&
                (this.toBeRescheduled == null || this.toBeRescheduled.Count == 0))
            {
                // we are idle after a ContinueAsNew - the batch is empty.
                // Wait for more messages to get here (via extended sessions)
                await this.doneProcessingMessages.Task;
            }

            if (!this.messageDataConverter.IsDefault)
            {
                innerContext.MessageDataConverter = this.messageDataConverter;
            }

            if (!this.errorDataConverter.IsDefault)
            {
                innerContext.ErrorDataConverter = this.errorDataConverter;
            }

            this.Config.TraceHelper.FunctionStarting(
                this.context.HubName,
                this.context.Name,
                this.context.InstanceId,
                this.Config.GetIntputOutputTrace(serializedInput),
                FunctionType.Entity,
                isReplay: false);

            if (this.NumberEventsToReceive > 0)
            {
                await this.doneProcessingMessages.Task;
            }

            // Commit the effects of this batch, if
            // we have not already run into an internal error
            // (in which case we will abort the batch instead of committing it)
            if (this.context.InternalError == null)
            {
                bool            writeBackSuccessful       = true;
                ResponseMessage serializationErrorMessage = null;

                if (this.RollbackFailedOperations)
                {
                    // the state has already been written back, since it is
                    // done right after each operation.
                }
                else
                {
                    // we are writing back the state here, after executing
                    // the entire batch of operations.
                    writeBackSuccessful = this.context.TryWriteback(out serializationErrorMessage);
                }

                // Reschedule all signals that were received before their time
                this.context.RescheduleMessages(innerContext, this.toBeRescheduled);

                // Send all buffered outgoing messages
                this.context.SendOutbox(innerContext, writeBackSuccessful, serializationErrorMessage);

                var jstate = JToken.FromObject(this.context.State);

                // continue as new
                innerContext.ContinueAsNew(jstate);
            }

            if (this.context.ErrorsPresent(out var description))
            {
                this.Config.TraceHelper.FunctionFailed(
                    this.context.HubName,
                    this.context.Name,
                    this.context.InstanceId,
                    description,
                    functionType: FunctionType.Entity,
                    isReplay: false);
            }
            else
            {
                this.Config.TraceHelper.FunctionCompleted(
                    this.context.HubName,
                    this.context.Name,
                    this.context.InstanceId,
                    this.Config.GetIntputOutputTrace(this.context.State.EntityState),
                    continuedAsNew: true,
                    functionType: FunctionType.Entity,
                    isReplay: false);
            }

            // The return value is not used.
            return(string.Empty);
        }