Skip to content

Commit 9a9462b

Browse files
committed
move generateFailedExecutionFromError to ExecutionDataService
1 parent 0300696 commit 9a9462b

File tree

7 files changed

+118
-111
lines changed

7 files changed

+118
-111
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { mock } from 'jest-mock-extended';
2+
import { NodeOperationError } from 'n8n-workflow';
3+
import type { INode, WorkflowExecuteMode } from 'n8n-workflow';
4+
5+
import { ExecutionDataService } from '../execution-data.service';
6+
7+
describe('ExecutionDataService', () => {
8+
const service = new ExecutionDataService();
9+
10+
describe('generateFailedExecutionFromError', () => {
11+
const mode: WorkflowExecuteMode = 'manual';
12+
const node = mock<INode>({ name: 'Test Node' });
13+
const error = new NodeOperationError(node, 'Test error message');
14+
15+
it('should generate a failed execution with error details', () => {
16+
const startTime = Date.now();
17+
18+
const result = service.generateFailedExecutionFromError(mode, error, node, startTime);
19+
20+
expect(result.mode).toBe(mode);
21+
expect(result.status).toBe('error');
22+
expect(result.startedAt).toBeInstanceOf(Date);
23+
expect(result.stoppedAt).toBeInstanceOf(Date);
24+
expect(result.data.resultData.error?.message).toBe(error.message);
25+
26+
const taskData = result.data.resultData.runData[node.name][0];
27+
expect(taskData.error?.message).toBe(error.message);
28+
expect(taskData.startTime).toBe(startTime);
29+
expect(taskData.executionStatus).toBe('error');
30+
expect(result.data.resultData.lastNodeExecuted).toBe(node.name);
31+
expect(result.data.executionData?.nodeExecutionStack[0].node).toEqual(node);
32+
});
33+
34+
it('should generate a failed execution without node details if node is undefined', () => {
35+
const result = service.generateFailedExecutionFromError(mode, error, undefined);
36+
37+
expect(result.mode).toBe(mode);
38+
expect(result.status).toBe('error');
39+
expect(result.startedAt).toBeInstanceOf(Date);
40+
expect(result.stoppedAt).toBeInstanceOf(Date);
41+
expect(result.data.resultData.error?.message).toBe(error.message);
42+
expect(result.data.resultData.runData).toEqual({});
43+
expect(result.data.resultData.lastNodeExecuted).toBeUndefined();
44+
expect(result.data.executionData).toBeUndefined();
45+
});
46+
});
47+
});

packages/cli/src/executions/__tests__/execution.service.test.ts

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { mock } from 'jest-mock-extended';
2-
import type { INode, WorkflowExecuteMode } from 'n8n-workflow';
3-
import { NodeOperationError, WorkflowOperationError } from 'n8n-workflow';
2+
import { WorkflowOperationError } from 'n8n-workflow';
43

54
import type { ActiveExecutions } from '@/active-executions';
65
import type { ConcurrencyControlService } from '@/concurrency/concurrency-control.service';
@@ -278,47 +277,4 @@ describe('ExecutionService', () => {
278277
});
279278
});
280279
});
281-
282-
describe('generateFailedExecutionFromError', () => {
283-
const mode: WorkflowExecuteMode = 'manual';
284-
const node = mock<INode>({ name: 'Test Node' });
285-
const error = new NodeOperationError(node, 'Test error message');
286-
287-
it('should generate a failed execution with error details', () => {
288-
const startTime = Date.now();
289-
290-
const result = executionService.generateFailedExecutionFromError(
291-
mode,
292-
error,
293-
node,
294-
startTime,
295-
);
296-
297-
expect(result.mode).toBe(mode);
298-
expect(result.status).toBe('error');
299-
expect(result.startedAt).toBeInstanceOf(Date);
300-
expect(result.stoppedAt).toBeInstanceOf(Date);
301-
expect(result.data.resultData.error?.message).toBe(error.message);
302-
303-
const taskData = result.data.resultData.runData[node.name][0];
304-
expect(taskData.error?.message).toBe(error.message);
305-
expect(taskData.startTime).toBe(startTime);
306-
expect(taskData.executionStatus).toBe('error');
307-
expect(result.data.resultData.lastNodeExecuted).toBe(node.name);
308-
expect(result.data.executionData?.nodeExecutionStack[0].node).toEqual(node);
309-
});
310-
311-
it('should generate a failed execution without node details if node is undefined', () => {
312-
const result = executionService.generateFailedExecutionFromError(mode, error, undefined);
313-
314-
expect(result.mode).toBe(mode);
315-
expect(result.status).toBe('error');
316-
expect(result.startedAt).toBeInstanceOf(Date);
317-
expect(result.stoppedAt).toBeInstanceOf(Date);
318-
expect(result.data.resultData.error?.message).toBe(error.message);
319-
expect(result.data.resultData.runData).toEqual({});
320-
expect(result.data.resultData.lastNodeExecuted).toBeUndefined();
321-
expect(result.data.executionData).toBeUndefined();
322-
});
323-
});
324280
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Service } from '@n8n/di';
2+
import type { ExecutionError, INode, IRun, WorkflowExecuteMode } from 'n8n-workflow';
3+
4+
@Service()
5+
export class ExecutionDataService {
6+
generateFailedExecutionFromError(
7+
mode: WorkflowExecuteMode,
8+
error: ExecutionError,
9+
node: INode | undefined,
10+
startTime = Date.now(),
11+
): IRun {
12+
const executionError = {
13+
...error,
14+
message: error.message,
15+
stack: error.stack,
16+
};
17+
const returnData: IRun = {
18+
data: {
19+
resultData: {
20+
error: executionError,
21+
runData: {},
22+
},
23+
},
24+
finished: false,
25+
mode,
26+
startedAt: new Date(),
27+
stoppedAt: new Date(),
28+
status: 'error',
29+
};
30+
31+
if (node) {
32+
returnData.data.startData = {
33+
destinationNode: node.name,
34+
runNodeFilter: [node.name],
35+
};
36+
returnData.data.resultData.lastNodeExecuted = node.name;
37+
returnData.data.resultData.runData[node.name] = [
38+
{
39+
startTime,
40+
executionTime: 0,
41+
executionStatus: 'error',
42+
error: executionError,
43+
source: [],
44+
},
45+
];
46+
returnData.data.executionData = {
47+
contextData: {},
48+
metadata: {},
49+
waitingExecution: {},
50+
waitingExecutionSource: {},
51+
nodeExecutionStack: [
52+
{
53+
node,
54+
data: {},
55+
source: null,
56+
},
57+
],
58+
};
59+
}
60+
return returnData;
61+
}
62+
}

packages/cli/src/executions/execution.service.ts

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import type {
1010
IWorkflowBase,
1111
WorkflowExecuteMode,
1212
IWorkflowExecutionDataProcess,
13-
IRun,
1413
} from 'n8n-workflow';
1514
import {
1615
ExecutionStatusList,
@@ -525,61 +524,4 @@ export class ExecutionService {
525524
await this.annotationTagMappingRepository.overwriteTags(annotation.id, updateData.tags);
526525
}
527526
}
528-
529-
generateFailedExecutionFromError(
530-
mode: WorkflowExecuteMode,
531-
error: ExecutionError,
532-
node: INode | undefined,
533-
startTime = Date.now(),
534-
): IRun {
535-
const executionError = {
536-
...error,
537-
message: error.message,
538-
stack: error.stack,
539-
};
540-
const returnData: IRun = {
541-
data: {
542-
resultData: {
543-
error: executionError,
544-
runData: {},
545-
},
546-
},
547-
finished: false,
548-
mode,
549-
startedAt: new Date(),
550-
stoppedAt: new Date(),
551-
status: 'error',
552-
};
553-
554-
if (node) {
555-
returnData.data.startData = {
556-
destinationNode: node.name,
557-
runNodeFilter: [node.name],
558-
};
559-
returnData.data.resultData.lastNodeExecuted = node.name;
560-
returnData.data.resultData.runData[node.name] = [
561-
{
562-
startTime,
563-
executionTime: 0,
564-
executionStatus: 'error',
565-
error: executionError,
566-
source: [],
567-
},
568-
];
569-
returnData.data.executionData = {
570-
contextData: {},
571-
metadata: {},
572-
waitingExecution: {},
573-
waitingExecutionSource: {},
574-
nodeExecutionStack: [
575-
{
576-
node,
577-
data: {},
578-
source: null,
579-
},
580-
],
581-
};
582-
}
583-
return returnData;
584-
}
585527
}

packages/cli/src/workflow-execute-additional-data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { WorkflowRepository } from '@/databases/repositories/workflow.repository
3737
import { EventService } from '@/events/event.service';
3838
import type { AiEventMap, AiEventPayload } from '@/events/maps/ai.event-map';
3939
import { getLifecycleHooksForSubExecutions } from '@/execution-lifecycle/execution-lifecycle-hooks';
40-
import { ExecutionService } from '@/executions/execution.service';
40+
import { ExecutionDataService } from '@/executions/execution-data.service';
4141
import {
4242
CredentialsPermissionChecker,
4343
SubworkflowPolicyChecker,
@@ -262,7 +262,7 @@ async function startExecution(
262262
data = await execution;
263263
} catch (error) {
264264
const executionError = error as ExecutionError;
265-
const fullRunData = Container.get(ExecutionService).generateFailedExecutionFromError(
265+
const fullRunData = Container.get(ExecutionDataService).generateFailedExecutionFromError(
266266
runData.executionMode,
267267
executionError,
268268
'node' in executionError ? executionError.node : undefined,

packages/cli/src/workflow-runner.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
getLifecycleHooksForScalingWorker,
2828
getLifecycleHooksForScalingMain,
2929
} from '@/execution-lifecycle/execution-lifecycle-hooks';
30-
import { ExecutionService } from '@/executions/execution.service';
30+
import { ExecutionDataService } from '@/executions/execution-data.service';
3131
import { CredentialsPermissionChecker } from '@/executions/pre-execution-checks';
3232
import { ManualExecutionService } from '@/manual-execution.service';
3333
import { NodeTypes } from '@/node-types';
@@ -52,7 +52,7 @@ export class WorkflowRunner {
5252
private readonly credentialsPermissionChecker: CredentialsPermissionChecker,
5353
private readonly instanceSettings: InstanceSettings,
5454
private readonly manualExecutionService: ManualExecutionService,
55-
private readonly executionService: ExecutionService,
55+
private readonly executionDataService: ExecutionDataService,
5656
) {}
5757

5858
/** The process did error */
@@ -137,7 +137,7 @@ export class WorkflowRunner {
137137
await this.credentialsPermissionChecker.check(workflowId, nodes);
138138
} catch (error) {
139139
// Create a failed execution with the data for the node, save it and abort execution
140-
const runData = this.executionService.generateFailedExecutionFromError(
140+
const runData = this.executionDataService.generateFailedExecutionFromError(
141141
data.executionMode,
142142
error,
143143
error.node,

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type { Project } from '@/databases/entities/project';
2121
import type { User } from '@/databases/entities/user';
2222
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
2323
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
24-
import { ExecutionService } from '@/executions/execution.service';
24+
import { ExecutionDataService } from '@/executions/execution-data.service';
2525
import { SubworkflowPolicyChecker } from '@/executions/pre-execution-checks';
2626
import type { CreateExecutionPayload, IWorkflowErrorData } from '@/interfaces';
2727
import { NodeTypes } from '@/node-types';
@@ -42,7 +42,7 @@ export class WorkflowExecutionService {
4242
private readonly workflowRunner: WorkflowRunner,
4343
private readonly globalConfig: GlobalConfig,
4444
private readonly subworkflowPolicyChecker: SubworkflowPolicyChecker,
45-
private readonly executionService: ExecutionService,
45+
private readonly executionDataService: ExecutionDataService,
4646
) {}
4747

4848
async runWorkflow(
@@ -274,7 +274,7 @@ export class WorkflowExecutionService {
274274
);
275275

276276
// Create a fake execution and save it to DB.
277-
const fakeExecution = this.executionService.generateFailedExecutionFromError(
277+
const fakeExecution = this.executionDataService.generateFailedExecutionFromError(
278278
'error',
279279
errorWorkflowPermissionError,
280280
initialNode,

0 commit comments

Comments
 (0)