mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 03:42:16 +00:00
feat: Implement new partial execution logic for acyclic workflows (no-changelog) (#10256)
Co-authored-by: Tomi Turtiainen <10324676+tomi@users.noreply.github.com>
This commit is contained in:
@@ -49,6 +49,16 @@ import {
|
||||
import get from 'lodash/get';
|
||||
import * as NodeExecuteFunctions from './NodeExecuteFunctions';
|
||||
|
||||
import * as assert from 'assert/strict';
|
||||
import { recreateNodeExecutionStack } from './PartialExecutionUtils/recreateNodeExecutionStack';
|
||||
import {
|
||||
DirectedGraph,
|
||||
findCycles,
|
||||
findStartNodes,
|
||||
findSubgraph,
|
||||
findTriggerForPartialExecution,
|
||||
} from './PartialExecutionUtils';
|
||||
|
||||
export class WorkflowExecute {
|
||||
private status: ExecutionStatus = 'new';
|
||||
|
||||
@@ -305,6 +315,82 @@ export class WorkflowExecute {
|
||||
return this.processRunExecutionData(workflow);
|
||||
}
|
||||
|
||||
// IMPORTANT: Do not add "async" to this function, it will then convert the
|
||||
// PCancelable to a regular Promise and does so not allow canceling
|
||||
// active executions anymore
|
||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
||||
runPartialWorkflow2(
|
||||
workflow: Workflow,
|
||||
runData: IRunData,
|
||||
destinationNodeName?: string,
|
||||
pinData?: IPinData,
|
||||
): PCancelable<IRun> {
|
||||
// TODO: Refactor the call-site to make `destinationNodeName` a required
|
||||
// after removing the old partial execution flow.
|
||||
assert.ok(
|
||||
destinationNodeName,
|
||||
'a destinationNodeName is required for the new partial execution flow',
|
||||
);
|
||||
|
||||
const destinationNode = workflow.getNode(destinationNodeName);
|
||||
assert.ok(
|
||||
destinationNode,
|
||||
`Could not find a node with the name ${destinationNodeName} in the workflow.`,
|
||||
);
|
||||
|
||||
// 1. Find the Trigger
|
||||
const trigger = findTriggerForPartialExecution(workflow, destinationNodeName);
|
||||
if (trigger === undefined) {
|
||||
throw new ApplicationError(
|
||||
'The destination node is not connected to any trigger. Partial executions need a trigger.',
|
||||
);
|
||||
}
|
||||
|
||||
// 2. Find the Subgraph
|
||||
const subgraph = findSubgraph(DirectedGraph.fromWorkflow(workflow), destinationNode, trigger);
|
||||
const filteredNodes = subgraph.getNodes();
|
||||
|
||||
// 3. Find the Start Nodes
|
||||
const startNodes = findStartNodes(subgraph, trigger, destinationNode, runData);
|
||||
|
||||
// 4. Detect Cycles
|
||||
const cycles = findCycles(workflow);
|
||||
|
||||
// 5. Handle Cycles
|
||||
if (cycles.length) {
|
||||
// TODO: handle
|
||||
}
|
||||
|
||||
// 6. Clean Run Data
|
||||
// TODO:
|
||||
|
||||
// 7. Recreate Execution Stack
|
||||
const { nodeExecutionStack, waitingExecution, waitingExecutionSource } =
|
||||
recreateNodeExecutionStack(subgraph, startNodes, destinationNode, runData, pinData ?? {});
|
||||
|
||||
// 8. Execute
|
||||
this.status = 'running';
|
||||
this.runExecutionData = {
|
||||
startData: {
|
||||
destinationNode: destinationNodeName,
|
||||
runNodeFilter: Array.from(filteredNodes.values()).map((node) => node.name),
|
||||
},
|
||||
resultData: {
|
||||
runData,
|
||||
pinData,
|
||||
},
|
||||
executionData: {
|
||||
contextData: {},
|
||||
nodeExecutionStack,
|
||||
metadata: {},
|
||||
waitingExecution,
|
||||
waitingExecutionSource,
|
||||
},
|
||||
};
|
||||
|
||||
return this.processRunExecutionData(subgraph.toWorkflow({ ...workflow }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the hook with the given name
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user