Esempio n. 1
0
 /// <summary>
 /// Logs that an event is being raised to an orchestration.
 /// </summary>
 /// <param name="target">The target orchestration instance.</param>
 /// <param name="raisedEvent">The event-raised event.</param>
 internal void RaisingEvent(OrchestrationInstance target, EventRaisedEvent raisedEvent)
 {
     if (this.IsStructuredLoggingEnabled)
     {
         this.WriteStructuredLog(new LogEvents.RaisingEvent(target, raisedEvent));
     }
 }
Esempio n. 2
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();
        }
Esempio n. 3
0
        async Task <OrchestrationInstance> InternalCreateOrchestrationInstanceWithRaisedEventAsync(
            string orchestrationName,
            string orchestrationVersion,
            string orchestrationInstanceId,
            object orchestrationInput,
            IDictionary <string, string> orchestrationTags,
            OrchestrationStatus[] dedupeStatuses,
            string eventName,
            object eventData,
            DateTime?startAt = null)
        {
            if (string.IsNullOrWhiteSpace(orchestrationInstanceId))
            {
                orchestrationInstanceId = Guid.NewGuid().ToString("N");
            }

            var orchestrationInstance = new OrchestrationInstance
            {
                InstanceId  = orchestrationInstanceId,
                ExecutionId = Guid.NewGuid().ToString("N"),
            };

            string serializedOrchestrationData = this.defaultConverter.Serialize(orchestrationInput);
            var    startedEvent = new ExecutionStartedEvent(-1, serializedOrchestrationData)
            {
                Tags    = orchestrationTags,
                Name    = orchestrationName,
                Version = orchestrationVersion,
                OrchestrationInstance = orchestrationInstance,
                ScheduledStartTime    = startAt
            };

            var startMessage = new TaskMessage
            {
                OrchestrationInstance = orchestrationInstance,
                Event = startedEvent
            };

            this.logHelper.SchedulingOrchestration(startedEvent);

            // Raised events and create orchestration calls use different methods so get handled separately
            await this.ServiceClient.CreateTaskOrchestrationAsync(startMessage, dedupeStatuses);

            if (eventData != null)
            {
                string serializedEventData = this.defaultConverter.Serialize(eventData);
                var    eventRaisedEvent    = new EventRaisedEvent(-1, serializedEventData)
                {
                    Name = eventName
                };
                this.logHelper.RaisingEvent(orchestrationInstance, eventRaisedEvent);

                var eventMessage = new TaskMessage
                {
                    OrchestrationInstance = new OrchestrationInstance
                    {
                        InstanceId = orchestrationInstanceId,

                        // to ensure that the event gets raised on the running
                        // orchestration instance, null the execution id
                        // so that it will find out which execution
                        // it should use for processing
                        ExecutionId = null
                    },
                    Event = eventRaisedEvent,
                };
                await this.ServiceClient.SendTaskOrchestrationMessageAsync(eventMessage);
            }

            return(orchestrationInstance);
        }
Esempio n. 4
0
        public static HistoryEvent GetHistoryEvent(this DbDataReader reader, bool isOrchestrationHistory = false)
        {
            string eventTypeString = (string)reader["EventType"];

            if (!Enum.TryParse(eventTypeString, out EventType eventType))
            {
                throw new InvalidOperationException($"Unknown event type '{eventTypeString}'.");
            }

            int eventId = GetTaskId(reader);

            HistoryEvent historyEvent;

            switch (eventType)
            {
            case EventType.ContinueAsNew:
                historyEvent = new ContinueAsNewEvent(eventId, GetPayloadText(reader));
                break;

            case EventType.EventRaised:
                historyEvent = new EventRaisedEvent(eventId, GetPayloadText(reader))
                {
                    Name = GetName(reader),
                };
                break;

            case EventType.EventSent:
                historyEvent = new EventSentEvent(eventId)
                {
                    Input      = GetPayloadText(reader),
                    Name       = GetName(reader),
                    InstanceId = GetInstanceId(reader),
                };
                break;

            case EventType.ExecutionCompleted:
                historyEvent = new ExecutionCompletedEvent(
                    eventId,
                    result: GetPayloadText(reader),
                    orchestrationStatus: OrchestrationStatus.Completed);
                break;

            case EventType.ExecutionFailed:
                historyEvent = new ExecutionCompletedEvent(
                    eventId,
                    result: GetPayloadText(reader),
                    orchestrationStatus: OrchestrationStatus.Failed);
                break;

            case EventType.ExecutionStarted:
                historyEvent = new ExecutionStartedEvent(eventId, GetPayloadText(reader))
                {
                    Name = GetName(reader),
                    OrchestrationInstance = new OrchestrationInstance
                    {
                        InstanceId  = GetInstanceId(reader),
                        ExecutionId = GetExecutionId(reader),
                    },
                    Tags    = null,  // TODO
                    Version = GetVersion(reader),
                };
                string?parentInstanceId = GetParentInstanceId(reader);
                if (parentInstanceId != null)
                {
                    ((ExecutionStartedEvent)historyEvent).ParentInstance = new ParentInstance
                    {
                        OrchestrationInstance = new OrchestrationInstance
                        {
                            InstanceId = parentInstanceId
                        },
                        TaskScheduleId = GetTaskId(reader)
                    };
                }
                break;

            case EventType.ExecutionTerminated:
                historyEvent = new ExecutionTerminatedEvent(eventId, GetPayloadText(reader));
                break;

            case EventType.GenericEvent:
                historyEvent = new GenericEvent(eventId, GetPayloadText(reader));
                break;

            case EventType.OrchestratorCompleted:
                historyEvent = new OrchestratorCompletedEvent(eventId);
                break;

            case EventType.OrchestratorStarted:
                historyEvent = new OrchestratorStartedEvent(eventId);
                break;

            case EventType.SubOrchestrationInstanceCompleted:
                historyEvent = new SubOrchestrationInstanceCompletedEvent(eventId, GetTaskId(reader), GetPayloadText(reader));
                break;

            case EventType.SubOrchestrationInstanceCreated:
                historyEvent = new SubOrchestrationInstanceCreatedEvent(eventId)
                {
                    Input      = GetPayloadText(reader),
                    InstanceId = null,     // TODO
                    Name       = GetName(reader),
                    Version    = null,
                };
                break;

            case EventType.SubOrchestrationInstanceFailed:
                historyEvent = new SubOrchestrationInstanceFailedEvent(
                    eventId,
                    taskScheduledId: GetTaskId(reader),
                    reason: GetReason(reader),
                    details: GetPayloadText(reader));
                break;

            case EventType.TaskCompleted:
                historyEvent = new TaskCompletedEvent(
                    eventId,
                    taskScheduledId: GetTaskId(reader),
                    result: GetPayloadText(reader));
                break;

            case EventType.TaskFailed:
                historyEvent = new TaskFailedEvent(
                    eventId,
                    taskScheduledId: GetTaskId(reader),
                    reason: GetReason(reader),
                    details: GetPayloadText(reader));
                break;

            case EventType.TaskScheduled:
                historyEvent = new TaskScheduledEvent(eventId)
                {
                    Input   = GetPayloadText(reader),
                    Name    = GetName(reader),
                    Version = GetVersion(reader),
                };
                break;

            case EventType.TimerCreated:
                historyEvent = new TimerCreatedEvent(eventId)
                {
                    FireAt = GetVisibleTime(reader),
                };
                break;

            case EventType.TimerFired:
                historyEvent = new TimerFiredEvent(eventId)
                {
                    FireAt  = GetVisibleTime(reader),
                    TimerId = GetTaskId(reader),
                };
                break;

            default:
                throw new InvalidOperationException($"Don't know how to interpret '{eventType}'.");
            }

            historyEvent.Timestamp = GetTimestamp(reader);
            historyEvent.IsPlayed  = isOrchestrationHistory && (bool)reader["IsPlayed"];
            return(historyEvent);
        }