UNPKG

n8n

Version:

n8n Workflow Automation Tool

293 lines 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WorkflowRunnerProcess = void 0; const n8n_core_1 = require("n8n-core"); const n8n_workflow_1 = require("n8n-workflow"); const _1 = require("."); const Logger_1 = require("./Logger"); const config = require("../config"); const InternalHooksManager_1 = require("./InternalHooksManager"); class WorkflowRunnerProcess { constructor() { this.startedAt = new Date(); this.childExecutions = {}; } static async stopProcess() { setTimeout(() => { process.exit(0); }, 30000); } async runWorkflow(inputData) { var _a; process.on('SIGTERM', WorkflowRunnerProcess.stopProcess); process.on('SIGINT', WorkflowRunnerProcess.stopProcess); const logger = (this.logger = Logger_1.getLogger()); n8n_workflow_1.LoggerProxy.init(logger); this.data = inputData; logger.verbose('Initializing n8n sub-process', { pid: process.pid, workflowId: this.data.workflowData.id, }); let className; let tempNode; let filePath; this.startedAt = new Date(); const nodeTypesData = {}; for (const nodeTypeName of Object.keys(this.data.nodeTypeData)) { className = this.data.nodeTypeData[nodeTypeName].className; filePath = this.data.nodeTypeData[nodeTypeName].sourcePath; const tempModule = require(filePath); try { const nodeObject = new tempModule[className](); if (nodeObject.getNodeType !== undefined) { tempNode = nodeObject.getNodeType(); } else { tempNode = nodeObject; } tempNode = new tempModule[className](); } catch (error) { throw new Error(`Error loading node "${nodeTypeName}" from: "${filePath}"`); } nodeTypesData[nodeTypeName] = { type: tempNode, sourcePath: filePath, }; } const nodeTypes = _1.NodeTypes(); await nodeTypes.init(nodeTypesData); const credentialTypes = _1.CredentialTypes(); await credentialTypes.init(inputData.credentialsTypeData); const credentialsOverwrites = _1.CredentialsOverwrites(); await credentialsOverwrites.init(inputData.credentialsOverwrite); const externalHooks = _1.ExternalHooks(); await externalHooks.init(); const instanceId = (_a = (await n8n_core_1.UserSettings.prepareUserSettings()).instanceId) !== null && _a !== void 0 ? _a : ''; InternalHooksManager_1.InternalHooksManager.init(instanceId); let shouldInitializaDb = false; inputData.workflowData.nodes.map((node) => { if (Object.keys(node.credentials === undefined ? {} : node.credentials).length > 0) { shouldInitializaDb = true; } }); if (shouldInitializaDb) { await _1.Db.init(); } else if (inputData.workflowData.settings !== undefined && inputData.workflowData.settings.saveExecutionProgress === true) { await _1.Db.init(); } else if (inputData.workflowData.settings !== undefined && inputData.workflowData.settings.saveExecutionProgress !== false && config.get('executions.saveExecutionProgress')) { await _1.Db.init(); } else if (inputData.workflowData.settings === undefined && config.get('executions.saveExecutionProgress')) { await _1.Db.init(); } let workflowTimeout = config.get('executions.timeout'); if (this.data.workflowData.settings && this.data.workflowData.settings.executionTimeout) { workflowTimeout = this.data.workflowData.settings.executionTimeout; } if (workflowTimeout > 0) { workflowTimeout = Math.min(workflowTimeout, config.get('executions.maxTimeout')); } this.workflow = new n8n_workflow_1.Workflow({ id: this.data.workflowData.id, name: this.data.workflowData.name, nodes: this.data.workflowData.nodes, connections: this.data.workflowData.connections, active: this.data.workflowData.active, nodeTypes, staticData: this.data.workflowData.staticData, settings: this.data.workflowData.settings, }); const additionalData = await _1.WorkflowExecuteAdditionalData.getBase(undefined, workflowTimeout <= 0 ? undefined : Date.now() + workflowTimeout * 1000); additionalData.hooks = this.getProcessForwardHooks(); additionalData.hooks.hookFunctions.sendResponse = [ async (response) => { await sendToParentProcess('sendResponse', { response: _1.WebhookHelpers.encodeWebhookResponse(response), }); }, ]; additionalData.executionId = inputData.executionId; additionalData.sendMessageToUI = async (source, message) => { if (workflowRunner.data.executionMode !== 'manual') { return; } try { await sendToParentProcess('sendMessageToUI', { source, message }); } catch (error) { this.logger.error(`There was a problem sending UI data to parent process: "${error.message}"`); } }; const executeWorkflowFunction = additionalData.executeWorkflow; additionalData.executeWorkflow = async (workflowInfo, additionalData, inputData) => { const workflowData = await _1.WorkflowExecuteAdditionalData.getWorkflowData(workflowInfo); const runData = await _1.WorkflowExecuteAdditionalData.getRunData(workflowData, inputData); await sendToParentProcess('startExecution', { runData }); const executionId = await new Promise((resolve) => { this.executionIdCallback = (executionId) => { resolve(executionId); }; }); let result; try { const executeWorkflowFunctionOutput = (await executeWorkflowFunction(workflowInfo, additionalData, inputData, executionId, workflowData, runData)); const { workflowExecute } = executeWorkflowFunctionOutput; this.childExecutions[executionId] = executeWorkflowFunctionOutput; const { workflow } = executeWorkflowFunctionOutput; result = await workflowExecute.processRunExecutionData(workflow); await externalHooks.run('workflow.postExecute', [result, workflowData]); void InternalHooksManager_1.InternalHooksManager.getInstance().onWorkflowPostExecute(workflowData, result); await sendToParentProcess('finishExecution', { executionId, result }); delete this.childExecutions[executionId]; } catch (e) { await sendToParentProcess('finishExecution', { executionId }); delete this.childExecutions[executionId]; throw e; } await sendToParentProcess('finishExecution', { executionId, result }); const returnData = _1.WorkflowHelpers.getDataLastExecutedNodeData(result); return returnData.data.main; }; if (this.data.executionData !== undefined) { this.workflowExecute = new n8n_core_1.WorkflowExecute(additionalData, this.data.executionMode, this.data.executionData); return this.workflowExecute.processRunExecutionData(this.workflow); } if (this.data.runData === undefined || this.data.startNodes === undefined || this.data.startNodes.length === 0 || this.data.destinationNode === undefined) { this.workflowExecute = new n8n_core_1.WorkflowExecute(additionalData, this.data.executionMode); return this.workflowExecute.run(this.workflow, undefined, this.data.destinationNode); } this.workflowExecute = new n8n_core_1.WorkflowExecute(additionalData, this.data.executionMode); return this.workflowExecute.runPartialWorkflow(this.workflow, this.data.runData, this.data.startNodes, this.data.destinationNode); } async sendHookToParentProcess(hook, parameters) { try { await sendToParentProcess('processHook', { hook, parameters, }); } catch (error) { this.logger.error(`There was a problem sending hook: "${hook}"`, { parameters, error }); } } getProcessForwardHooks() { const hookFunctions = { nodeExecuteBefore: [ async (nodeName) => { await this.sendHookToParentProcess('nodeExecuteBefore', [nodeName]); }, ], nodeExecuteAfter: [ async (nodeName, data) => { await this.sendHookToParentProcess('nodeExecuteAfter', [nodeName, data]); }, ], workflowExecuteBefore: [ async () => { await this.sendHookToParentProcess('workflowExecuteBefore', []); }, ], workflowExecuteAfter: [ async (fullRunData, newStaticData) => { await this.sendHookToParentProcess('workflowExecuteAfter', [fullRunData, newStaticData]); }, ], }; const preExecuteFunctions = _1.WorkflowExecuteAdditionalData.hookFunctionsPreExecute(); for (const key of Object.keys(preExecuteFunctions)) { if (hookFunctions[key] === undefined) { hookFunctions[key] = []; } hookFunctions[key].push.apply(hookFunctions[key], preExecuteFunctions[key]); } return new n8n_workflow_1.WorkflowHooks(hookFunctions, this.data.executionMode, this.data.executionId, this.data.workflowData, { sessionId: this.data.sessionId, retryOf: this.data.retryOf }); } } exports.WorkflowRunnerProcess = WorkflowRunnerProcess; async function sendToParentProcess(type, data) { return new Promise((resolve, reject) => { process.send({ type, data, }, (error) => { if (error) { return reject(error); } resolve(); }); }); } const workflowRunner = new WorkflowRunnerProcess(); process.on('message', async (message) => { try { if (message.type === 'startWorkflow') { await sendToParentProcess('start', {}); const runData = await workflowRunner.runWorkflow(message.data); await sendToParentProcess('end', { runData, }); process.exit(); } else if (message.type === 'stopExecution' || message.type === 'timeout') { let runData; if (workflowRunner.workflowExecute !== undefined) { const executionIds = Object.keys(workflowRunner.childExecutions); for (const executionId of executionIds) { const childWorkflowExecute = workflowRunner.childExecutions[executionId]; runData = childWorkflowExecute.workflowExecute.getFullRunData(workflowRunner.childExecutions[executionId].startedAt); const timeOutError = message.type === 'timeout' ? new n8n_workflow_1.WorkflowOperationError('Workflow execution timed out!') : new n8n_workflow_1.WorkflowOperationError('Workflow-Execution has been canceled!'); await childWorkflowExecute.workflowExecute.processSuccessExecution(workflowRunner.childExecutions[executionId].startedAt, childWorkflowExecute.workflow, timeOutError); } runData = workflowRunner.workflowExecute.getFullRunData(workflowRunner.startedAt); const timeOutError = message.type === 'timeout' ? new n8n_workflow_1.WorkflowOperationError('Workflow execution timed out!') : new n8n_workflow_1.WorkflowOperationError('Workflow-Execution has been canceled!'); await workflowRunner.workflowExecute.processSuccessExecution(workflowRunner.startedAt, workflowRunner.workflow, timeOutError); } else { runData = { data: { resultData: { runData: {}, }, }, finished: false, mode: workflowRunner.data ? workflowRunner.data.executionMode : 'own', startedAt: workflowRunner.startedAt, stoppedAt: new Date(), }; workflowRunner.sendHookToParentProcess('workflowExecuteAfter', [runData]); } await sendToParentProcess(message.type === 'timeout' ? message.type : 'end', { runData, }); process.exit(); } else if (message.type === 'executionId') { workflowRunner.executionIdCallback(message.data.executionId); } } catch (error) { const executionError = Object.assign(Object.assign({}, error), { name: error.name || 'Error', message: error.message, stack: error.stack }); await sendToParentProcess('processError', { executionError, }); process.exit(); } }); //# sourceMappingURL=WorkflowRunnerProcess.js.map