Esempio n. 1
0
 public TaskEntityShim(DurableTaskExtension config, string schedulerId)
     : base(config)
 {
     this.SchedulerId = schedulerId;
     this.EntityId    = EntityId.GetEntityIdFromSchedulerId(schedulerId);
     this.context     = new DurableEntityContext(config, this.EntityId, this);
 }
 public TaskEntityShim(DurableTaskExtension config, DurabilityProvider durabilityProvider, string schedulerId)
     : base(config)
 {
     this.messageDataConverter = config.MessageDataConverter;
     this.errorDataConverter   = config.ErrorDataConverter;
     this.SchedulerId          = schedulerId;
     this.EntityId             = EntityId.GetEntityIdFromSchedulerId(schedulerId);
     this.context = new DurableEntityContext(config, durabilityProvider, this.EntityId, this);
 }
Esempio n. 3
0
            private static string EntityContextToString(DurableEntityContext arg)
            {
                // assemble the operation batch information
                var operationBatch = new JArray();

                foreach (var operation in arg.OperationBatch)
                {
                    operationBatch.Add(new JObject(
                                           new JProperty("name", operation.Operation),
                                           new JProperty("input", operation.Input),
                                           new JProperty("isSignal", operation.IsSignal)));
                }

                // assemble the entity state information
                var contextObject = new JObject(
                    new JProperty("self", new JObject(
                                      new JProperty("name", arg.Self.EntityName),
                                      new JProperty("key", arg.Self.EntityKey))),
                    new JProperty("exists", arg.State.EntityExists),
                    new JProperty("state", arg.State.EntityState),
                    new JProperty("batch", operationBatch));

                return(contextObject.ToString());
            }
Esempio n. 4
0
        private async Task EntityMiddleware(DispatchMiddlewareContext dispatchContext, Func <Task> next)
        {
            var entityShim = dispatchContext.GetProperty <TaskOrchestration>() as TaskEntityShim;

            if (entityShim == null)
            {
                // This is not an entity - skip.
                await next();

                return;
            }

            OrchestrationRuntimeState runtimeState  = dispatchContext.GetProperty <OrchestrationRuntimeState>();
            DurableEntityContext      entityContext = (DurableEntityContext)entityShim.Context;

            entityContext.InstanceId  = runtimeState.OrchestrationInstance.InstanceId;
            entityContext.ExecutionId = runtimeState.OrchestrationInstance.ExecutionId;
            entityContext.History     = runtimeState.Events;
            entityContext.RawInput    = runtimeState.Input;

            try
            {
                // 1. First time through the history
                // we count events, add any under-lock op to the batch, and process lock releases
                foreach (HistoryEvent e in runtimeState.Events)
                {
                    switch (e.EventType)
                    {
                    case EventType.ExecutionStarted:
                        entityShim.Rehydrate(runtimeState.Input);
                        break;

                    case EventType.EventRaised:
                        EventRaisedEvent eventRaisedEvent = (EventRaisedEvent)e;

                        this.TraceHelper.DeliveringEntityMessage(
                            entityContext.InstanceId,
                            entityContext.ExecutionId,
                            e.EventId,
                            eventRaisedEvent.Name,
                            eventRaisedEvent.Input);

                        entityShim.NumberEventsToReceive++;

                        if (eventRaisedEvent.Name == "op")
                        {
                            // we are receiving an operation request or a lock request
                            var requestMessage = JsonConvert.DeserializeObject <RequestMessage>(eventRaisedEvent.Input);

                            // run this through the message sorter to help with reordering and duplicate filtering
                            var deliverNow = entityContext.State.MessageSorter.ReceiveInOrder(requestMessage, entityContext.EntityMessageReorderWindow);

                            foreach (var message in deliverNow)
                            {
                                if (entityContext.State.LockedBy == message.ParentInstanceId)
                                {
                                    // operation requests from the lock holder are processed immediately
                                    entityShim.AddOperationToBatch(message);
                                }
                                else
                                {
                                    // others go to the back of the queue
                                    entityContext.State.Enqueue(message);
                                }
                            }
                        }
                        else
                        {
                            // we are receiving a lock release
                            var message = JsonConvert.DeserializeObject <ReleaseMessage>(eventRaisedEvent.Input);

                            if (entityContext.State.LockedBy == message.ParentInstanceId)
                            {
                                this.TraceHelper.EntityLockReleased(
                                    entityContext.HubName,
                                    entityContext.Name,
                                    entityContext.InstanceId,
                                    message.ParentInstanceId,
                                    message.LockRequestId,
                                    isReplay: false);

                                entityContext.State.LockedBy = null;
                            }
                        }

                        break;
                    }
                }

                // 2. We add as many requests from the queue to the batch as possible (stopping at lock requests)
                while (entityContext.State.LockedBy == null &&
                       entityContext.State.TryDequeue(out var request))
                {
                    if (request.IsLockRequest)
                    {
                        entityShim.AddLockRequestToBatch(request);
                        entityContext.State.LockedBy = request.ParentInstanceId;
                    }
                    else
                    {
                        entityShim.AddOperationToBatch(request);
                    }
                }
            }
            catch (Exception e)
            {
                entityContext.CaptureInternalError(e);
            }

            // 3. Start the functions invocation pipeline (billing, logging, bindings, and timeout tracking).
            FunctionResult result = await entityShim.GetFunctionInfo().Executor.TryExecuteAsync(
                new TriggeredFunctionData
            {
                TriggerValue = entityShim.Context,

#pragma warning disable CS0618 // Approved for use by this extension
                InvokeHandler = async userCodeInvoker =>
                {
                    entityShim.SetFunctionInvocationCallback(userCodeInvoker);

                    // 3. Run all the operations in the batch
                    if (entityContext.InternalError == null)
                    {
                        try
                        {
                            await entityShim.ExecuteBatch();
                        }
                        catch (Exception e)
                        {
                            entityContext.CaptureInternalError(e);
                        }
                    }

                    // 4. Run the DTFx orchestration to persist the effects,
                    // send the outbox, and continue as new
                    await next();

                    // 5. If there were internal or application errors, indicate to the functions host
                    entityContext.ThrowInternalExceptionIfAny();
                    entityContext.ThrowApplicationExceptionsIfAny();
                },
#pragma warning restore CS0618
            },
                CancellationToken.None);

            await entityContext.RunDeferredTasks();

            // If there were internal errors, do not commit the batch, but instead rethrow
            // here so DTFx can abort the batch and back off the work item
            entityContext.ThrowInternalExceptionIfAny();
        }