n8n
Version:
n8n Workflow Automation Tool
329 lines • 16.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLifecycleHooksForSubExecutions = getLifecycleHooksForSubExecutions;
exports.getLifecycleHooksForScalingWorker = getLifecycleHooksForScalingWorker;
exports.getLifecycleHooksForScalingMain = getLifecycleHooksForScalingMain;
exports.getLifecycleHooksForRegularMain = getLifecycleHooksForRegularMain;
const di_1 = require("@n8n/di");
const flatted_1 = require("flatted");
const n8n_core_1 = require("n8n-core");
const execution_repository_1 = require("../databases/repositories/execution.repository");
const module_1 = require("../decorators/module");
const event_service_1 = require("../events/event.service");
const external_hooks_1 = require("../external-hooks");
const push_1 = require("../push");
const workflow_statistics_service_1 = require("../services/workflow-statistics.service");
const utils_1 = require("../utils");
const workflow_static_data_service_1 = require("../workflows/workflow-static-data.service");
const execute_error_workflow_1 = require("./execute-error-workflow");
const restore_binary_data_id_1 = require("./restore-binary-data-id");
const save_execution_progress_1 = require("./save-execution-progress");
const shared_hook_functions_1 = require("./shared/shared-hook-functions");
const to_save_settings_1 = require("./to-save-settings");
function hookFunctionsWorkflowEvents(hooks, userId) {
const eventService = di_1.Container.get(event_service_1.EventService);
hooks.addHandler('workflowExecuteBefore', function () {
const { executionId, workflowData } = this;
eventService.emit('workflow-pre-execute', { executionId, data: workflowData });
});
hooks.addHandler('workflowExecuteAfter', function (runData) {
if (runData.status === 'waiting')
return;
const { executionId, workflowData: workflow } = this;
eventService.emit('workflow-post-execute', { executionId, runData, workflow, userId });
});
}
function hookFunctionsNodeEvents(hooks) {
const eventService = di_1.Container.get(event_service_1.EventService);
hooks.addHandler('nodeExecuteBefore', function (nodeName) {
const { executionId, workflowData: workflow } = this;
eventService.emit('node-pre-execute', { executionId, workflow, nodeName });
});
hooks.addHandler('nodeExecuteAfter', function (nodeName) {
const { executionId, workflowData: workflow } = this;
eventService.emit('node-post-execute', { executionId, workflow, nodeName });
});
}
function hookFunctionsPush(hooks, { pushRef, retryOf }) {
if (!pushRef)
return;
const logger = di_1.Container.get(n8n_core_1.Logger);
const pushInstance = di_1.Container.get(push_1.Push);
hooks.addHandler('nodeExecuteBefore', function (nodeName, data) {
const { executionId } = this;
logger.debug(`Executing hook on node "${nodeName}" (hookFunctionsPush)`, {
executionId,
pushRef,
workflowId: this.workflowData.id,
});
pushInstance.send({ type: 'nodeExecuteBefore', data: { executionId, nodeName, data } }, pushRef);
});
hooks.addHandler('nodeExecuteAfter', function (nodeName, data) {
const { executionId } = this;
logger.debug(`Executing hook on node "${nodeName}" (hookFunctionsPush)`, {
executionId,
pushRef,
workflowId: this.workflowData.id,
});
pushInstance.send({ type: 'nodeExecuteAfter', data: { executionId, nodeName, data } }, pushRef);
});
hooks.addHandler('workflowExecuteBefore', function (_workflow, data) {
const { executionId } = this;
const { id: workflowId, name: workflowName } = this.workflowData;
logger.debug('Executing hook (hookFunctionsPush)', {
executionId,
pushRef,
workflowId,
});
pushInstance.send({
type: 'executionStarted',
data: {
executionId,
mode: this.mode,
startedAt: new Date(),
retryOf,
workflowId,
workflowName,
flattedRunData: data?.resultData.runData
? (0, flatted_1.stringify)(data.resultData.runData)
: (0, flatted_1.stringify)({}),
},
}, pushRef);
});
hooks.addHandler('workflowExecuteAfter', function (fullRunData) {
const { executionId } = this;
const { id: workflowId } = this.workflowData;
logger.debug('Executing hook (hookFunctionsPush)', {
executionId,
pushRef,
workflowId,
});
const { status } = fullRunData;
if (status === 'waiting') {
pushInstance.send({ type: 'executionWaiting', data: { executionId } }, pushRef);
}
else {
const rawData = (0, flatted_1.stringify)(fullRunData.data);
pushInstance.send({ type: 'executionFinished', data: { executionId, workflowId, status, rawData } }, pushRef);
}
});
}
function hookFunctionsExternalHooks(hooks) {
const externalHooks = di_1.Container.get(external_hooks_1.ExternalHooks);
hooks.addHandler('workflowExecuteBefore', async function (workflow) {
await externalHooks.run('workflow.preExecute', [workflow, this.mode]);
});
hooks.addHandler('workflowExecuteAfter', async function (fullRunData) {
await externalHooks.run('workflow.postExecute', [
fullRunData,
this.workflowData,
this.executionId,
]);
});
}
function hookFunctionsSaveProgress(hooks, { saveSettings }) {
if (!saveSettings.progress)
return;
hooks.addHandler('nodeExecuteAfter', async function (nodeName, data, executionData) {
await (0, save_execution_progress_1.saveExecutionProgress)(this.workflowData.id, this.executionId, nodeName, data, executionData);
});
}
function hookFunctionsFinalizeExecutionStatus(hooks) {
hooks.addHandler('workflowExecuteAfter', (fullRunData) => {
fullRunData.status = (0, shared_hook_functions_1.determineFinalExecutionStatus)(fullRunData);
});
}
function hookFunctionsStatistics(hooks) {
const workflowStatisticsService = di_1.Container.get(workflow_statistics_service_1.WorkflowStatisticsService);
hooks.addHandler('nodeFetchedData', (workflowId, node) => {
workflowStatisticsService.emit('nodeFetchedData', { workflowId, node });
});
}
function hookFunctionsSave(hooks, { pushRef, retryOf, saveSettings }) {
const logger = di_1.Container.get(n8n_core_1.Logger);
const errorReporter = di_1.Container.get(n8n_core_1.ErrorReporter);
const executionRepository = di_1.Container.get(execution_repository_1.ExecutionRepository);
const workflowStaticDataService = di_1.Container.get(workflow_static_data_service_1.WorkflowStaticDataService);
const workflowStatisticsService = di_1.Container.get(workflow_statistics_service_1.WorkflowStatisticsService);
hooks.addHandler('workflowExecuteAfter', async function (fullRunData, newStaticData) {
logger.debug('Executing hook (hookFunctionsSave)', {
executionId: this.executionId,
workflowId: this.workflowData.id,
});
await (0, restore_binary_data_id_1.restoreBinaryDataId)(fullRunData, this.executionId, this.mode);
const isManualMode = this.mode === 'manual';
try {
if (!isManualMode && (0, utils_1.isWorkflowIdValid)(this.workflowData.id) && newStaticData) {
try {
await workflowStaticDataService.saveStaticDataById(this.workflowData.id, newStaticData);
}
catch (e) {
errorReporter.error(e);
logger.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: "${e.message}" (hookFunctionsSave)`, { executionId: this.executionId, workflowId: this.workflowData.id });
}
}
if (isManualMode && !saveSettings.manual && !fullRunData.waitTill) {
await executionRepository.softDelete(this.executionId);
return;
}
const shouldNotSave = (fullRunData.status === 'success' && !saveSettings.success) ||
(fullRunData.status !== 'success' && !saveSettings.error);
if (shouldNotSave && !fullRunData.waitTill && !isManualMode) {
(0, execute_error_workflow_1.executeErrorWorkflow)(this.workflowData, fullRunData, this.mode, this.executionId, retryOf);
await executionRepository.hardDelete({
workflowId: this.workflowData.id,
executionId: this.executionId,
});
return;
}
const fullExecutionData = (0, shared_hook_functions_1.prepareExecutionDataForDbUpdate)({
runData: fullRunData,
workflowData: this.workflowData,
workflowStatusFinal: fullRunData.status,
retryOf,
});
if (fullRunData.waitTill && isManualMode) {
fullExecutionData.data.pushRef = pushRef;
}
await (0, shared_hook_functions_1.updateExistingExecution)({
executionId: this.executionId,
workflowId: this.workflowData.id,
executionData: fullExecutionData,
});
if (!isManualMode) {
(0, execute_error_workflow_1.executeErrorWorkflow)(this.workflowData, fullRunData, this.mode, this.executionId, retryOf);
}
}
finally {
workflowStatisticsService.emit('workflowExecutionCompleted', {
workflowData: this.workflowData,
fullRunData,
});
}
});
}
function hookFunctionsSaveWorker(hooks, { pushRef, retryOf }) {
const logger = di_1.Container.get(n8n_core_1.Logger);
const errorReporter = di_1.Container.get(n8n_core_1.ErrorReporter);
const workflowStaticDataService = di_1.Container.get(workflow_static_data_service_1.WorkflowStaticDataService);
const workflowStatisticsService = di_1.Container.get(workflow_statistics_service_1.WorkflowStatisticsService);
hooks.addHandler('workflowExecuteAfter', async function (fullRunData, newStaticData) {
logger.debug('Executing hook (hookFunctionsSaveWorker)', {
executionId: this.executionId,
workflowId: this.workflowData.id,
});
const isManualMode = this.mode === 'manual';
try {
if (!isManualMode && (0, utils_1.isWorkflowIdValid)(this.workflowData.id) && newStaticData) {
try {
await workflowStaticDataService.saveStaticDataById(this.workflowData.id, newStaticData);
}
catch (e) {
errorReporter.error(e);
logger.error(`There was a problem saving the workflow with id "${this.workflowData.id}" to save changed staticData: "${e.message}" (workflowExecuteAfter)`, { workflowId: this.workflowData.id });
}
}
if (!isManualMode && fullRunData.status !== 'success' && fullRunData.status !== 'waiting') {
(0, execute_error_workflow_1.executeErrorWorkflow)(this.workflowData, fullRunData, this.mode, this.executionId, retryOf);
}
const fullExecutionData = (0, shared_hook_functions_1.prepareExecutionDataForDbUpdate)({
runData: fullRunData,
workflowData: this.workflowData,
workflowStatusFinal: fullRunData.status,
retryOf,
});
if (fullRunData.waitTill && isManualMode) {
fullExecutionData.data.pushRef = pushRef;
}
await (0, shared_hook_functions_1.updateExistingExecution)({
executionId: this.executionId,
workflowId: this.workflowData.id,
executionData: fullExecutionData,
});
}
finally {
workflowStatisticsService.emit('workflowExecutionCompleted', {
workflowData: this.workflowData,
fullRunData,
});
}
});
}
function getLifecycleHooksForSubExecutions(mode, executionId, workflowData, userId) {
const hooks = new n8n_core_1.ExecutionLifecycleHooks(mode, executionId, workflowData);
const saveSettings = (0, to_save_settings_1.toSaveSettings)(workflowData.settings);
hookFunctionsWorkflowEvents(hooks, userId);
hookFunctionsNodeEvents(hooks);
hookFunctionsFinalizeExecutionStatus(hooks);
hookFunctionsSave(hooks, { saveSettings });
hookFunctionsSaveProgress(hooks, { saveSettings });
hookFunctionsStatistics(hooks);
hookFunctionsExternalHooks(hooks);
return hooks;
}
function getLifecycleHooksForScalingWorker(data, executionId) {
const { pushRef, retryOf, executionMode, workflowData } = data;
const hooks = new n8n_core_1.ExecutionLifecycleHooks(executionMode, executionId, workflowData);
const saveSettings = (0, to_save_settings_1.toSaveSettings)(workflowData.settings);
const optionalParameters = { pushRef, retryOf: retryOf ?? undefined, saveSettings };
hookFunctionsNodeEvents(hooks);
hookFunctionsFinalizeExecutionStatus(hooks);
hookFunctionsSaveWorker(hooks, optionalParameters);
hookFunctionsSaveProgress(hooks, optionalParameters);
hookFunctionsStatistics(hooks);
hookFunctionsExternalHooks(hooks);
if (executionMode === 'manual' && di_1.Container.get(n8n_core_1.InstanceSettings).isWorker) {
hookFunctionsPush(hooks, optionalParameters);
}
di_1.Container.get(module_1.ModuleRegistry).registerLifecycleHooks(hooks);
return hooks;
}
function getLifecycleHooksForScalingMain(data, executionId) {
const { pushRef, retryOf, executionMode, workflowData, userId } = data;
const hooks = new n8n_core_1.ExecutionLifecycleHooks(executionMode, executionId, workflowData);
const saveSettings = (0, to_save_settings_1.toSaveSettings)(workflowData.settings);
const optionalParameters = { pushRef, retryOf: retryOf ?? undefined, saveSettings };
const executionRepository = di_1.Container.get(execution_repository_1.ExecutionRepository);
hookFunctionsWorkflowEvents(hooks, userId);
hookFunctionsSaveProgress(hooks, optionalParameters);
hookFunctionsExternalHooks(hooks);
hookFunctionsFinalizeExecutionStatus(hooks);
hooks.addHandler('workflowExecuteAfter', async function (fullRunData) {
if (!fullRunData.finished)
return;
const isManualMode = this.mode === 'manual';
if (isManualMode && !saveSettings.manual && !fullRunData.waitTill) {
await executionRepository.softDelete(this.executionId);
return;
}
const shouldNotSave = (fullRunData.status === 'success' && !saveSettings.success) ||
(fullRunData.status !== 'success' && !saveSettings.error);
if (!isManualMode && shouldNotSave && !fullRunData.waitTill) {
await executionRepository.hardDelete({
workflowId: this.workflowData.id,
executionId: this.executionId,
});
}
});
hooks.handlers.nodeExecuteBefore = [];
hooks.handlers.nodeExecuteAfter = [];
di_1.Container.get(module_1.ModuleRegistry).registerLifecycleHooks(hooks);
return hooks;
}
function getLifecycleHooksForRegularMain(data, executionId) {
const { pushRef, retryOf, executionMode, workflowData, userId } = data;
const hooks = new n8n_core_1.ExecutionLifecycleHooks(executionMode, executionId, workflowData);
const saveSettings = (0, to_save_settings_1.toSaveSettings)(workflowData.settings);
const optionalParameters = { pushRef, retryOf: retryOf ?? undefined, saveSettings };
hookFunctionsWorkflowEvents(hooks, userId);
hookFunctionsNodeEvents(hooks);
hookFunctionsFinalizeExecutionStatus(hooks);
hookFunctionsSave(hooks, optionalParameters);
hookFunctionsPush(hooks, optionalParameters);
hookFunctionsSaveProgress(hooks, optionalParameters);
hookFunctionsStatistics(hooks);
hookFunctionsExternalHooks(hooks);
di_1.Container.get(module_1.ModuleRegistry).registerLifecycleHooks(hooks);
return hooks;
}
//# sourceMappingURL=execution-lifecycle-hooks.js.map