in src/orchestrations/TaskOrchestrationExecutor.ts [354:424]
private tryResumingUserCode(): void {
// If the current task does not have a result,
// then we cannot continue running the user code.
const currentTask: TaskBase = this.currentTask;
this.context.isReplaying = currentTask.isPlayed;
if (currentTask.stateObj === TaskState.Running) {
return;
}
// We feed in the result of the current task to the generator
let newTask: TaskBase | undefined = undefined;
try {
// In the WhenAny-case, the result of the current task is another Task.
// Here, we make sure not to expose the internal task class by extracting
// the user-facing representation of the task.
const result = currentTask.result;
const taskValue = result;
const taskSucceeded = currentTask.stateObj === TaskState.Completed;
// If the task succeeded, we feed the task result as a value;
// otherwise, we feed it as an exception.
const generatorResult = taskSucceeded
? this.generator.next(taskValue)
: this.generator.throw(taskValue);
if (generatorResult.done) {
// If the generator returned (via a `return` statement),
// then we capture the workflow's result result.
this.orchestratorReturned = true;
this.output = generatorResult.value;
return;
} else if (generatorResult.value instanceof DFTask) {
// The generator yielded another task.
newTask = generatorResult.value;
} else {
// non-task was yielded. This isn't supported
let errorMsg = `Durable Functions programming constraint violation: Orchestration yielded data of type ${typeof generatorResult.value}.`;
errorMsg +=
typeof generatorResult.value === "undefined"
? ' This is likely a result of yielding a "fire-and-forget API" such as signalEntity or continueAsNew.' +
" These APIs should not be yielded as they are not blocking operations. Please remove the yield statement preceding those invocations." +
" If you are not calling those APIs, p"
: " Only Task types can be yielded. P";
errorMsg +=
"lease check your yield statements to make sure you only yield Task types resulting from calling Durable Functions APIs.";
throw Error(errorMsg);
}
} catch (exception) {
// The generator threw an exception
this.exception = exception;
}
if (newTask !== undefined) {
// The generator returned an already-completed task,
// so we try to run the user code again.
this.currentTask = newTask;
if (newTask.state !== TaskState.Running) {
this.tryResumingUserCode();
} else {
// The task hasn't completed, we add it to the open (incomplete) task list
this.trackOpenTask(newTask);
// We only keep track of actions from user-declared tasks, not from
// tasks generated internally to facilitate history-processing.
if (this.currentTask instanceof DFTask && !this.currentTask.alreadyScheduled) {
this.markAsScheduled(this.currentTask);
this.addToActions(this.currentTask.actionObj);
}
}
}
}