in src/WebJobs.Extensions.DurableTask/Listener/TaskOrchestrationShim.cs [137:209]
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 an "illegal await" (awaiting a non DF API) is detected, we throw an exception.
// This exception will not transition the orchestrator to a Failed state.
// TODO: look to fail orchestrator in illegal awaits. This may require DTFx support.
this.context.ThrowIfInvalidAccess();
if (returnValue != null)
{
if (orchestratorInfo.IsOutOfProc)
{
await this.TraceAndReplay(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 != null
&& orchestratorInfo.IsOutOfProc
&& OutOfProcExceptionHelpers.TryExtractOutOfProcStateJson(e.InnerException, out string returnValue)
&& !string.IsNullOrEmpty(returnValue))
{
try
{
await this.TraceAndReplay(returnValue, e);
}
catch (OrchestrationFailureException ex)
{
this.TraceAndSendExceptionNotification(ex);
this.context.OrchestrationException = ExceptionDispatchInfo.Capture(ex);
throw;
}
}
else
{
this.TraceAndSendExceptionNotification(e);
var orchestrationException = new OrchestrationFailureException(
$"Orchestrator function '{this.context.Name}' failed: {e.Message}",
Utils.SerializeCause(e, innerContext.ErrorDataConverter));
this.context.OrchestrationException =
ExceptionDispatchInfo.Capture(orchestrationException);
DurableTaskExtension.TagActivityWithOrchestrationStatus(OrchestrationRuntimeStatus.Failed, this.context.InstanceId);
throw orchestrationException;
}
}
finally
{
this.context.IsCompleted = true;
}
}