refactor(core): Move ExecutionLifecycleHooks to core (#13042)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2025-02-07 18:16:37 +01:00
committed by GitHub
parent cae98e733d
commit d41ca832dc
24 changed files with 911 additions and 886 deletions

View File

@@ -3,6 +3,7 @@
/* eslint-disable @typescript-eslint/no-shadow */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { Container, Service } from '@n8n/di';
import type { ExecutionLifecycleHooks } from 'n8n-core';
import { ErrorReporter, InstanceSettings, Logger, WorkflowExecute } from 'n8n-core';
import type {
ExecutionError,
@@ -11,7 +12,6 @@ import type {
IPinData,
IRun,
WorkflowExecuteMode,
WorkflowHooks,
IWorkflowExecutionDataProcess,
} from 'n8n-workflow';
import { ExecutionCancelledError, Workflow } from 'n8n-workflow';
@@ -22,9 +22,9 @@ import config from '@/config';
import { ExecutionRepository } from '@/databases/repositories/execution.repository';
import { ExecutionNotFoundError } from '@/errors/execution-not-found-error';
import {
getWorkflowHooksMain,
getWorkflowHooksWorkerExecuter,
getWorkflowHooksWorkerMain,
getLifecycleHooksForRegularMain,
getLifecycleHooksForScalingWorker,
getLifecycleHooksForScalingMain,
} from '@/execution-lifecycle/execution-lifecycle-hooks';
import { ManualExecutionService } from '@/manual-execution.service';
import { NodeTypes } from '@/node-types';
@@ -61,7 +61,7 @@ export class WorkflowRunner {
startedAt: Date,
executionMode: WorkflowExecuteMode,
executionId: string,
hooks?: WorkflowHooks,
hooks?: ExecutionLifecycleHooks,
) {
// This means the execution was probably cancelled and has already
// been cleaned up.
@@ -116,9 +116,7 @@ export class WorkflowRunner {
// set the execution to failed.
this.activeExecutions.finalizeExecution(executionId, fullRunData);
if (hooks) {
await hooks.executeHookFunctions('workflowExecuteAfter', [fullRunData]);
}
await hooks?.runHook('workflowExecuteAfter', [fullRunData]);
}
/** Run the workflow
@@ -140,12 +138,9 @@ export class WorkflowRunner {
} catch (error) {
// Create a failed execution with the data for the node, save it and abort execution
const runData = generateFailedExecutionFromError(data.executionMode, error, error.node);
const workflowHooks = getWorkflowHooksMain(data, executionId);
await workflowHooks.executeHookFunctions('workflowExecuteBefore', [
undefined,
data.executionData,
]);
await workflowHooks.executeHookFunctions('workflowExecuteAfter', [runData]);
const lifecycleHooks = getLifecycleHooksForRegularMain(data, executionId);
await lifecycleHooks.runHook('workflowExecuteBefore', [undefined, data.executionData]);
await lifecycleHooks.runHook('workflowExecuteAfter', [runData]);
responsePromise?.reject(error);
this.activeExecutions.finalizeExecution(executionId);
return executionId;
@@ -250,13 +245,12 @@ export class WorkflowRunner {
await this.executionRepository.setRunning(executionId); // write
try {
additionalData.hooks = getWorkflowHooksMain(data, executionId);
const lifecycleHooks = getLifecycleHooksForRegularMain(data, executionId);
additionalData.hooks = lifecycleHooks;
additionalData.hooks.hookFunctions.sendResponse = [
async (response: IExecuteResponsePromiseData): Promise<void> => {
this.activeExecutions.resolveResponsePromise(executionId, response);
},
];
lifecycleHooks.addHandler('sendResponse', (response) => {
this.activeExecutions.resolveResponsePromise(executionId, response);
});
additionalData.setExecutionStatus = WorkflowExecuteAdditionalData.setExecutionStatus.bind({
executionId,
@@ -347,27 +341,32 @@ export class WorkflowRunner {
// TODO: For realtime jobs should probably also not do retry or not retry if they are older than x seconds.
// Check if they get retried by default and how often.
let job: Job;
let hooks: WorkflowHooks;
let lifecycleHooks: ExecutionLifecycleHooks;
try {
job = await this.scalingService.addJob(jobData, { priority: realtime ? 50 : 100 });
hooks = getWorkflowHooksWorkerMain(data.executionMode, executionId, data.workflowData, {
retryOf: data.retryOf ?? undefined,
});
lifecycleHooks = getLifecycleHooksForScalingMain(
data.executionMode,
executionId,
data.workflowData,
{
retryOf: data.retryOf ?? undefined,
},
);
// Normally also workflow should be supplied here but as it only used for sending
// data to editor-UI is not needed.
await hooks.executeHookFunctions('workflowExecuteBefore', [undefined, data.executionData]);
await lifecycleHooks.runHook('workflowExecuteBefore', [undefined, data.executionData]);
} catch (error) {
// We use "getWorkflowHooksWorkerExecuter" as "getWorkflowHooksWorkerMain" does not contain the
// We use "getLifecycleHooksForScalingWorker" as "getLifecycleHooksForScalingMain" does not contain the
// "workflowExecuteAfter" which we require.
const hooks = getWorkflowHooksWorkerExecuter(
const lifecycleHooks = getLifecycleHooksForScalingWorker(
data.executionMode,
executionId,
data.workflowData,
{ retryOf: data.retryOf ?? undefined },
);
await this.processError(error, new Date(), data.executionMode, executionId, hooks);
await this.processError(error, new Date(), data.executionMode, executionId, lifecycleHooks);
throw error;
}
@@ -377,9 +376,9 @@ export class WorkflowRunner {
onCancel(async () => {
await this.scalingService.stopJob(job);
// We use "getWorkflowHooksWorkerExecuter" as "getWorkflowHooksWorkerMain" does not contain the
// We use "getLifecycleHooksForScalingWorker" as "getLifecycleHooksForScalingMain" does not contain the
// "workflowExecuteAfter" which we require.
const hooksWorker = getWorkflowHooksWorkerExecuter(
const lifecycleHooks = getLifecycleHooksForScalingWorker(
data.executionMode,
executionId,
data.workflowData,
@@ -387,7 +386,13 @@ export class WorkflowRunner {
);
const error = new ExecutionCancelledError(executionId);
await this.processError(error, new Date(), data.executionMode, executionId, hooksWorker);
await this.processError(
error,
new Date(),
data.executionMode,
executionId,
lifecycleHooks,
);
reject(error);
});
@@ -402,16 +407,22 @@ export class WorkflowRunner {
error = new MaxStalledCountError(error);
}
// We use "getWorkflowHooksWorkerExecuter" as "getWorkflowHooksWorkerMain" does not contain the
// We use "getLifecycleHooksForScalingWorker" as "getLifecycleHooksForScalingMain" does not contain the
// "workflowExecuteAfter" which we require.
const hooks = getWorkflowHooksWorkerExecuter(
const lifecycleHooks = getLifecycleHooksForScalingWorker(
data.executionMode,
executionId,
data.workflowData,
{ retryOf: data.retryOf ?? undefined },
);
await this.processError(error, new Date(), data.executionMode, executionId, hooks);
await this.processError(
error,
new Date(),
data.executionMode,
executionId,
lifecycleHooks,
);
reject(error);
}
@@ -437,7 +448,7 @@ export class WorkflowRunner {
// Normally also static data should be supplied here but as it only used for sending
// data to editor-UI is not needed.
await hooks.executeHookFunctions('workflowExecuteAfter', [runData]);
await lifecycleHooks.runHook('workflowExecuteAfter', [runData]);
resolve(runData);
},