Skip to content

Commit d64f2e5

Browse files
authored
feat(core): Link 'Error Trigger' nodes to the parent execution that errored (#16016)
1 parent 52a9d4b commit d64f2e5

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

packages/cli/src/workflows/__tests__/workflow-execution.service.test.ts

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { User } from '@n8n/db';
1+
import type { GlobalConfig } from '@n8n/config';
2+
import type { Project, User, WorkflowEntity, WorkflowRepository } from '@n8n/db';
23
import { mock } from 'jest-mock-extended';
34
import {
45
NodeConnectionTypes,
@@ -7,8 +8,10 @@ import {
78
type INodeType,
89
type IWorkflowBase,
910
type IWorkflowExecuteAdditionalData,
11+
type ExecutionError,
1012
} from 'n8n-workflow';
1113

14+
import type { IWorkflowErrorData } from '@/interfaces';
1215
import type { NodeTypes } from '@/node-types';
1316
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
1417
import type { WorkflowRunner } from '@/workflow-runner';
@@ -490,6 +493,113 @@ describe('WorkflowExecutionService', () => {
490493
});
491494
});
492495
});
496+
497+
describe('executeErrorWorkflow()', () => {
498+
test('should call `WorkflowRunner.run()` with correct parameters', async () => {
499+
const workflowErrorData: IWorkflowErrorData = {
500+
workflow: { id: 'workflow-id', name: 'Test Workflow' },
501+
execution: {
502+
id: 'execution-id',
503+
mode: 'manual',
504+
error: new Error('Test error') as ExecutionError,
505+
lastNodeExecuted: 'Node with error',
506+
},
507+
};
508+
509+
const workflowRunnerMock = mock<WorkflowRunner>();
510+
workflowRunnerMock.run.mockResolvedValue('fake-execution-id');
511+
512+
const errorTriggerType = 'n8n-nodes-base.errorTrigger';
513+
const globalConfig = mock<GlobalConfig>({
514+
nodes: {
515+
errorTriggerType,
516+
},
517+
});
518+
519+
const errorTriggerNode: INode = {
520+
id: 'error-trigger-node-id',
521+
name: 'Error Trigger',
522+
type: errorTriggerType,
523+
typeVersion: 1,
524+
position: [0, 0],
525+
parameters: {},
526+
};
527+
528+
const errorWorkflow = mock<WorkflowEntity>({
529+
id: 'error-workflow-id',
530+
name: 'Error Workflow',
531+
active: false,
532+
isArchived: false,
533+
pinData: {},
534+
nodes: [errorTriggerNode],
535+
connections: {},
536+
createdAt: new Date(),
537+
updatedAt: new Date(),
538+
});
539+
540+
const workflowRepositoryMock = mock<WorkflowRepository>();
541+
workflowRepositoryMock.findOneBy.mockResolvedValue(errorWorkflow);
542+
543+
const service = new WorkflowExecutionService(
544+
mock(),
545+
mock(),
546+
mock(),
547+
workflowRepositoryMock,
548+
nodeTypes,
549+
mock(),
550+
workflowRunnerMock,
551+
globalConfig,
552+
mock(),
553+
mock(),
554+
);
555+
556+
await service.executeErrorWorkflow(
557+
'error-workflow-id',
558+
workflowErrorData,
559+
mock<Project>({ id: 'project-id' }),
560+
);
561+
562+
expect(workflowRunnerMock.run).toHaveBeenCalledTimes(1);
563+
expect(workflowRunnerMock.run).toHaveBeenCalledWith({
564+
executionMode: 'error',
565+
executionData: {
566+
executionData: {
567+
contextData: {},
568+
metadata: {},
569+
nodeExecutionStack: [
570+
{
571+
node: errorTriggerNode,
572+
data: {
573+
main: [
574+
[
575+
{
576+
json: workflowErrorData,
577+
},
578+
],
579+
],
580+
},
581+
source: null,
582+
metadata: {
583+
parentExecution: {
584+
executionId: 'execution-id',
585+
workflowId: 'workflow-id',
586+
},
587+
},
588+
},
589+
],
590+
waitingExecution: {},
591+
waitingExecutionSource: {},
592+
},
593+
resultData: {
594+
runData: {},
595+
},
596+
startData: {},
597+
},
598+
workflowData: errorWorkflow,
599+
projectId: 'project-id',
600+
});
601+
});
602+
});
493603
});
494604

495605
function createMainConnection(targetNode: string, sourceNode: string): IConnections {

packages/cli/src/workflows/workflow-execution.service.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,14 @@ export class WorkflowExecutionService {
320320
return;
321321
}
322322

323+
const parentExecution =
324+
workflowErrorData.execution?.id && workflowErrorData.workflow?.id
325+
? {
326+
executionId: workflowErrorData.execution.id,
327+
workflowId: workflowErrorData.workflow.id,
328+
}
329+
: undefined;
330+
323331
// Can execute without webhook so go on
324332
// Initialize the data of the webhook node
325333
const nodeExecutionStack: IExecuteData[] = [];
@@ -335,6 +343,11 @@ export class WorkflowExecutionService {
335343
],
336344
},
337345
source: null,
346+
...(parentExecution && {
347+
metadata: {
348+
parentExecution,
349+
},
350+
}),
338351
});
339352

340353
const runExecutionData: IRunExecutionData = {

0 commit comments

Comments
 (0)