in src/DurableTask.Core/OrchestrationRuntimeState.cs [266:319]
void SetMarkerEvents(HistoryEvent historyEvent)
{
if (historyEvent is ExecutionStartedEvent startedEvent)
{
if (ExecutionStartedEvent != null)
{
throw new InvalidOperationException(
"Multiple ExecutionStartedEvent found, potential corruption in state storage");
}
ExecutionStartedEvent = startedEvent;
}
else if (historyEvent is ExecutionCompletedEvent completedEvent)
{
if (ExecutionCompletedEvent == null)
{
ExecutionCompletedEvent = completedEvent;
orchestrationStatus = completedEvent.OrchestrationStatus;
}
else
{
// It's not generally expected to receive multiple execution completed events for a given orchestrator, but it's possible under certain race conditions.
// For example: when an orchestrator is signaled to terminate at the same time as it attempts to continue-as-new.
var log = $"Received new {completedEvent.GetType().Name} event despite the orchestration being already in the {orchestrationStatus} state.";
if (orchestrationStatus == OrchestrationStatus.ContinuedAsNew && completedEvent.OrchestrationStatus == OrchestrationStatus.Terminated)
{
// If the orchestration planned to continue-as-new but termination is requested, we transition to the terminated state.
// This is because termination should be considered to be forceful.
log += " Discarding previous 'ExecutionCompletedEvent' as termination is forceful.";
ExecutionCompletedEvent = completedEvent;
orchestrationStatus = completedEvent.OrchestrationStatus;
}
else
{
// otherwise, we ignore the new event.
log += " Discarding new 'ExecutionCompletedEvent'.";
}
LogHelper?.OrchestrationDebugTrace(this.OrchestrationInstance?.InstanceId ?? "", this.OrchestrationInstance?.ExecutionId ?? "", log);
}
}
else if (historyEvent is ExecutionSuspendedEvent)
{
orchestrationStatus = OrchestrationStatus.Suspended;
}
else if (historyEvent is ExecutionResumedEvent)
{
if (ExecutionCompletedEvent == null)
{
orchestrationStatus = OrchestrationStatus.Running;
}
}
}