Skip to content

Commit

Permalink
fix(core): Restore log event n8n.workflow.failed (n8n-io#10253)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivov authored Jul 31, 2024
1 parent efee25d commit 3e96b29
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 5 deletions.
2 changes: 2 additions & 0 deletions packages/cli/src/WorkflowExecuteAdditionalData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks {
executionId,
success: runData.status === 'success',
isManual: runData.mode === 'manual',
runData,
});
},
async function (this: WorkflowHooks, fullRunData: IRun) {
Expand Down Expand Up @@ -940,6 +941,7 @@ async function executeWorkflow(
success: data.status === 'success',
isManual: data.mode === 'manual',
userId: additionalData.userId,
runData: data,
});

// subworkflow either finished, or is in status waiting due to a wait node, both cases are considered successes here
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/WorkflowRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export class WorkflowRunner {
success: executionData?.status === 'success',
isManual: data.executionMode === 'manual',
userId: data.userId,
runData: executionData,
});
if (this.externalHooks.exists('workflow.postExecute')) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { mock } from 'jest-mock-extended';
import { AuditEventRelay } from '../audit-event-relay.service';
import type { MessageEventBus } from '../MessageEventBus/MessageEventBus';
import type { Event } from '../event.types';
import type { EventService } from '../event.service';
import { EventService } from '../event.service';
import type { INode, IRun } from 'n8n-workflow';

describe('AuditorService', () => {
const eventBus = mock<MessageEventBus>();
const eventService = mock<EventService>();
const eventService = new EventService();
const auditor = new AuditEventRelay(eventService, eventBus);
auditor.init();

afterEach(() => {
jest.clearAllMocks();
Expand Down Expand Up @@ -80,4 +82,67 @@ describe('AuditorService', () => {
},
});
});

it('should log on `workflow-post-execute` for successful execution', () => {
const payload = mock<Event['workflow-post-execute']>({
executionId: 'some-id',
success: true,
userId: 'some-id',
workflowId: 'some-id',
isManual: true,
workflowName: 'some-name',
metadata: {},
runData: mock<IRun>({ data: { resultData: {} } }),
});

eventService.emit('workflow-post-execute', payload);

const { runData: _, ...rest } = payload;

expect(eventBus.sendWorkflowEvent).toHaveBeenCalledWith({
eventName: 'n8n.workflow.success',
payload: rest,
});
});

it('should handle `workflow-post-execute` event for unsuccessful execution', () => {
const runData = mock<IRun>({
data: {
resultData: {
lastNodeExecuted: 'some-node',
// @ts-expect-error Partial mock
error: {
node: mock<INode>({ type: 'some-type' }),
message: 'some-message',
},
errorMessage: 'some-message',
},
},
}) as unknown as IRun;

const event = {
executionId: 'some-id',
success: false,
userId: 'some-id',
workflowId: 'some-id',
isManual: true,
workflowName: 'some-name',
metadata: {},
runData,
};

eventService.emit('workflow-post-execute', event);

const { runData: _, ...rest } = event;

expect(eventBus.sendWorkflowEvent).toHaveBeenCalledWith({
eventName: 'n8n.workflow.failed',
payload: {
...rest,
lastNodeExecuted: 'some-node',
errorNodeType: 'some-type',
errorMessage: 'some-message',
},
});
});
});
23 changes: 21 additions & 2 deletions packages/cli/src/eventbus/audit-event-relay.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,28 @@ export class AuditEventRelay {
}

private workflowPostExecute(event: Event['workflow-post-execute']) {
const { runData, ...rest } = event;

if (event.success) {
void this.eventBus.sendWorkflowEvent({
eventName: 'n8n.workflow.success',
payload: rest,
});

return;
}

void this.eventBus.sendWorkflowEvent({
eventName: 'n8n.workflow.success',
payload: event,
eventName: 'n8n.workflow.failed',
payload: {
...rest,
lastNodeExecuted: runData?.data.resultData.lastNodeExecuted,
errorNodeType:
runData?.data.resultData.error && 'node' in runData?.data.resultData.error
? runData?.data.resultData.error.node?.type
: undefined,
errorMessage: runData?.data.resultData.error?.message.toString(),
},
});
}

Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/eventbus/event.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AuthenticationMethod, IWorkflowBase } from 'n8n-workflow';
import type { AuthenticationMethod, IRun, IWorkflowBase } from 'n8n-workflow';
import type { IWorkflowExecutionDataProcess } from '@/Interfaces';
import type { ProjectRole } from '@/databases/entities/ProjectRelation';
import type { GlobalRole } from '@/databases/entities/User';
Expand Down Expand Up @@ -46,6 +46,7 @@ export type Event = {
isManual: boolean;
workflowName: string;
metadata?: Record<string, string>;
runData?: IRun;
};

'node-pre-execute': {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/executions/execution-recovery.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ export class ExecutionRecoveryService {
executionId: execution.id,
success: execution.status === 'success',
isManual: execution.mode === 'manual',
runData: execution,
});

const externalHooks = getWorkflowHooksMain(
Expand Down

0 comments on commit 3e96b29

Please sign in to comment.