mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-02 07:01:30 -08:00
refactor(core): Encapsulate manual execution flow in WorkflowRunner
(#12135)
This commit is contained in:
parent
eb7d5934ef
commit
b37e5142b2
|
@ -20,6 +20,7 @@ import type {
|
||||||
WorkflowHooks,
|
WorkflowHooks,
|
||||||
IWorkflowExecutionDataProcess,
|
IWorkflowExecutionDataProcess,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
|
IWorkflowExecuteAdditionalData,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
import {
|
import {
|
||||||
ErrorReporterProxy as ErrorReporter,
|
ErrorReporterProxy as ErrorReporter,
|
||||||
|
@ -295,88 +296,8 @@ export class WorkflowRunner {
|
||||||
data.executionData,
|
data.executionData,
|
||||||
);
|
);
|
||||||
workflowExecution = workflowExecute.processRunExecutionData(workflow);
|
workflowExecution = workflowExecute.processRunExecutionData(workflow);
|
||||||
} else if (data.triggerToStartFrom?.data && data.startNodes && !data.destinationNode) {
|
|
||||||
this.logger.debug(
|
|
||||||
`Execution ID ${executionId} had triggerToStartFrom. Starting from that trigger.`,
|
|
||||||
{ executionId },
|
|
||||||
);
|
|
||||||
const startNodes = data.startNodes.map((data) => {
|
|
||||||
const node = workflow.getNode(data.name);
|
|
||||||
a.ok(node, `Could not find a node named "${data.name}" in the workflow.`);
|
|
||||||
return node;
|
|
||||||
});
|
|
||||||
const runData = { [data.triggerToStartFrom.name]: [data.triggerToStartFrom.data] };
|
|
||||||
|
|
||||||
const { nodeExecutionStack, waitingExecution, waitingExecutionSource } =
|
|
||||||
recreateNodeExecutionStack(
|
|
||||||
filterDisabledNodes(DirectedGraph.fromWorkflow(workflow)),
|
|
||||||
new Set(startNodes),
|
|
||||||
runData,
|
|
||||||
data.pinData ?? {},
|
|
||||||
);
|
|
||||||
const executionData: IRunExecutionData = {
|
|
||||||
resultData: { runData, pinData },
|
|
||||||
executionData: {
|
|
||||||
contextData: {},
|
|
||||||
metadata: {},
|
|
||||||
nodeExecutionStack,
|
|
||||||
waitingExecution,
|
|
||||||
waitingExecutionSource,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const workflowExecute = new WorkflowExecute(additionalData, 'manual', executionData);
|
|
||||||
workflowExecution = workflowExecute.processRunExecutionData(workflow);
|
|
||||||
} else if (
|
|
||||||
data.runData === undefined ||
|
|
||||||
data.startNodes === undefined ||
|
|
||||||
data.startNodes.length === 0
|
|
||||||
) {
|
|
||||||
// Full Execution
|
|
||||||
// TODO: When the old partial execution logic is removed this block can
|
|
||||||
// be removed and the previous one can be merged into
|
|
||||||
// `workflowExecute.runPartialWorkflow2`.
|
|
||||||
// Partial executions then require either a destination node from which
|
|
||||||
// everything else can be derived, or a triggerToStartFrom with
|
|
||||||
// triggerData.
|
|
||||||
this.logger.debug(`Execution ID ${executionId} will run executing all nodes.`, {
|
|
||||||
executionId,
|
|
||||||
});
|
|
||||||
// Execute all nodes
|
|
||||||
|
|
||||||
const startNode = WorkflowHelpers.getExecutionStartNode(data, workflow);
|
|
||||||
|
|
||||||
// Can execute without webhook so go on
|
|
||||||
const workflowExecute = new WorkflowExecute(additionalData, data.executionMode);
|
|
||||||
workflowExecution = workflowExecute.run(
|
|
||||||
workflow,
|
|
||||||
startNode,
|
|
||||||
data.destinationNode,
|
|
||||||
data.pinData,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Partial Execution
|
workflowExecution = this.runManually(data, workflow, additionalData, executionId, pinData);
|
||||||
this.logger.debug(`Execution ID ${executionId} is a partial execution.`, { executionId });
|
|
||||||
// Execute only the nodes between start and destination nodes
|
|
||||||
const workflowExecute = new WorkflowExecute(additionalData, data.executionMode);
|
|
||||||
|
|
||||||
if (data.partialExecutionVersion === '1') {
|
|
||||||
workflowExecution = workflowExecute.runPartialWorkflow2(
|
|
||||||
workflow,
|
|
||||||
data.runData,
|
|
||||||
data.pinData,
|
|
||||||
data.dirtyNodeNames,
|
|
||||||
data.destinationNode,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
workflowExecution = workflowExecute.runPartialWorkflow(
|
|
||||||
workflow,
|
|
||||||
data.runData,
|
|
||||||
data.startNodes,
|
|
||||||
data.destinationNode,
|
|
||||||
data.pinData,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activeExecutions.attachWorkflowExecution(executionId, workflowExecution);
|
this.activeExecutions.attachWorkflowExecution(executionId, workflowExecution);
|
||||||
|
@ -539,4 +460,92 @@ export class WorkflowRunner {
|
||||||
|
|
||||||
this.activeExecutions.attachWorkflowExecution(executionId, workflowExecution);
|
this.activeExecutions.attachWorkflowExecution(executionId, workflowExecution);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
||||||
|
runManually(
|
||||||
|
data: IWorkflowExecutionDataProcess,
|
||||||
|
workflow: Workflow,
|
||||||
|
additionalData: IWorkflowExecuteAdditionalData,
|
||||||
|
executionId: string,
|
||||||
|
pinData?: IPinData,
|
||||||
|
) {
|
||||||
|
if (data.triggerToStartFrom?.data && data.startNodes && !data.destinationNode) {
|
||||||
|
this.logger.debug(
|
||||||
|
`Execution ID ${executionId} had triggerToStartFrom. Starting from that trigger.`,
|
||||||
|
{ executionId },
|
||||||
|
);
|
||||||
|
const startNodes = data.startNodes.map((data) => {
|
||||||
|
const node = workflow.getNode(data.name);
|
||||||
|
a.ok(node, `Could not find a node named "${data.name}" in the workflow.`);
|
||||||
|
return node;
|
||||||
|
});
|
||||||
|
const runData = { [data.triggerToStartFrom.name]: [data.triggerToStartFrom.data] };
|
||||||
|
|
||||||
|
const { nodeExecutionStack, waitingExecution, waitingExecutionSource } =
|
||||||
|
recreateNodeExecutionStack(
|
||||||
|
filterDisabledNodes(DirectedGraph.fromWorkflow(workflow)),
|
||||||
|
new Set(startNodes),
|
||||||
|
runData,
|
||||||
|
data.pinData ?? {},
|
||||||
|
);
|
||||||
|
const executionData: IRunExecutionData = {
|
||||||
|
resultData: { runData, pinData },
|
||||||
|
executionData: {
|
||||||
|
contextData: {},
|
||||||
|
metadata: {},
|
||||||
|
nodeExecutionStack,
|
||||||
|
waitingExecution,
|
||||||
|
waitingExecutionSource,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const workflowExecute = new WorkflowExecute(additionalData, 'manual', executionData);
|
||||||
|
return workflowExecute.processRunExecutionData(workflow);
|
||||||
|
} else if (
|
||||||
|
data.runData === undefined ||
|
||||||
|
data.startNodes === undefined ||
|
||||||
|
data.startNodes.length === 0
|
||||||
|
) {
|
||||||
|
// Full Execution
|
||||||
|
// TODO: When the old partial execution logic is removed this block can
|
||||||
|
// be removed and the previous one can be merged into
|
||||||
|
// `workflowExecute.runPartialWorkflow2`.
|
||||||
|
// Partial executions then require either a destination node from which
|
||||||
|
// everything else can be derived, or a triggerToStartFrom with
|
||||||
|
// triggerData.
|
||||||
|
this.logger.debug(`Execution ID ${executionId} will run executing all nodes.`, {
|
||||||
|
executionId,
|
||||||
|
});
|
||||||
|
// Execute all nodes
|
||||||
|
|
||||||
|
const startNode = WorkflowHelpers.getExecutionStartNode(data, workflow);
|
||||||
|
|
||||||
|
// Can execute without webhook so go on
|
||||||
|
const workflowExecute = new WorkflowExecute(additionalData, data.executionMode);
|
||||||
|
return workflowExecute.run(workflow, startNode, data.destinationNode, data.pinData);
|
||||||
|
} else {
|
||||||
|
// Partial Execution
|
||||||
|
this.logger.debug(`Execution ID ${executionId} is a partial execution.`, { executionId });
|
||||||
|
// Execute only the nodes between start and destination nodes
|
||||||
|
const workflowExecute = new WorkflowExecute(additionalData, data.executionMode);
|
||||||
|
|
||||||
|
if (data.partialExecutionVersion === '1') {
|
||||||
|
return workflowExecute.runPartialWorkflow2(
|
||||||
|
workflow,
|
||||||
|
data.runData,
|
||||||
|
data.pinData,
|
||||||
|
data.dirtyNodeNames,
|
||||||
|
data.destinationNode,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return workflowExecute.runPartialWorkflow(
|
||||||
|
workflow,
|
||||||
|
data.runData,
|
||||||
|
data.startNodes,
|
||||||
|
data.destinationNode,
|
||||||
|
data.pinData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue