UNPKG

n8n

Version:

n8n Workflow Automation Tool

180 lines 9.89 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExecutionDataRecoveryService = void 0; const typedi_1 = require("typedi"); const push_1 = require("../push"); const InternalHooks_1 = require("../InternalHooks"); const n8n_workflow_1 = require("n8n-workflow"); const execution_repository_1 = require("../databases/repositories/execution.repository"); const WorkflowExecuteAdditionalData_1 = require("../WorkflowExecuteAdditionalData"); let ExecutionDataRecoveryService = class ExecutionDataRecoveryService { constructor(push, executionRepository) { this.push = push; this.executionRepository = executionRepository; } async recoverExecutionData(executionId, messages, applyToDb) { var _a, _b, _c, _d; const executionEntry = await this.executionRepository.findSingleExecution(executionId, { includeData: true, unflattenData: true, }); if (executionEntry && messages) { let executionData = executionEntry.data; let workflowError; if (!executionData) { executionData = { resultData: { runData: {} } }; } let nodeNames = []; if (((_a = executionData === null || executionData === void 0 ? void 0 : executionData.resultData) === null || _a === void 0 ? void 0 : _a.runData) && Object.keys(executionData.resultData.runData).length > 0) { } else { if (!executionData.resultData) { executionData.resultData = { runData: {}, }; } else { if (!executionData.resultData.runData) { executionData.resultData.runData = {}; } } } nodeNames = executionEntry.workflowData.nodes.map((n) => n.name); let lastNodeRunTimestamp = undefined; for (const nodeName of nodeNames) { const nodeByName = executionEntry === null || executionEntry === void 0 ? void 0 : executionEntry.workflowData.nodes.find((n) => n.name === nodeName); if (!nodeByName) continue; const nodeStartedMessage = messages.find((message) => message.eventName === 'n8n.node.started' && message.payload.nodeName === nodeName); const nodeFinishedMessage = messages.find((message) => message.eventName === 'n8n.node.finished' && message.payload.nodeName === nodeName); const executionTime = nodeStartedMessage && nodeFinishedMessage ? nodeFinishedMessage.ts.diff(nodeStartedMessage.ts).toMillis() : 0; let taskData; if (((_b = executionData.resultData.runData[nodeName]) === null || _b === void 0 ? void 0 : _b.length) > 0) { taskData = executionData.resultData.runData[nodeName][0]; } else { taskData = { startTime: nodeStartedMessage ? nodeStartedMessage.ts.toUnixInteger() : 0, executionTime, source: [null], executionStatus: 'unknown', }; } if (nodeStartedMessage && !nodeFinishedMessage) { const nodeError = new n8n_workflow_1.NodeOperationError(nodeByName, 'Node crashed, possible out-of-memory issue', { message: 'Execution stopped at this node', description: "n8n may have run out of memory while executing it. More context and tips on how to avoid this <a href='https://docs.n8n.io/flow-logic/error-handling/memory-errors' target='_blank'>in the docs</a>", }); workflowError = new n8n_workflow_1.WorkflowOperationError('Workflow did not finish, possible out-of-memory issue'); taskData.error = nodeError; taskData.executionStatus = 'crashed'; executionData.resultData.lastNodeExecuted = nodeName; if (nodeStartedMessage) lastNodeRunTimestamp = nodeStartedMessage.ts; } else if (nodeStartedMessage && nodeFinishedMessage) { taskData.executionStatus = 'success'; if (taskData.data === undefined) { taskData.data = { main: [ [ { json: { isArtificialRecoveredEventItem: true, }, pairedItem: undefined, }, ], ], }; } } if (!executionData.resultData.runData[nodeName]) { executionData.resultData.runData[nodeName] = [taskData]; } } if (!lastNodeRunTimestamp) { const workflowEndedMessage = messages.find((message) => [ 'n8n.workflow.success', 'n8n.workflow.crashed', 'n8n.workflow.failed', ].includes(message.eventName)); if (workflowEndedMessage) { lastNodeRunTimestamp = workflowEndedMessage.ts; } else { if (!workflowError) { workflowError = new n8n_workflow_1.WorkflowOperationError('Workflow did not finish, possible out-of-memory issue'); } const workflowStartedMessage = messages.find((message) => message.eventName === 'n8n.workflow.started'); if (workflowStartedMessage) { lastNodeRunTimestamp = workflowStartedMessage.ts; } } } if (!executionData.resultData.error && workflowError) { executionData.resultData.error = workflowError; } if (applyToDb) { const newStatus = executionEntry.status === 'error' ? 'error' : 'crashed'; await this.executionRepository.updateExistingExecution(executionId, { data: executionData, status: newStatus, stoppedAt: lastNodeRunTimestamp === null || lastNodeRunTimestamp === void 0 ? void 0 : lastNodeRunTimestamp.toJSDate(), }); await typedi_1.Container.get(InternalHooks_1.InternalHooks).onWorkflowPostExecute(executionId, executionEntry.workflowData, { data: executionData, finished: false, mode: executionEntry.mode, waitTill: (_c = executionEntry.waitTill) !== null && _c !== void 0 ? _c : undefined, startedAt: executionEntry.startedAt, stoppedAt: lastNodeRunTimestamp === null || lastNodeRunTimestamp === void 0 ? void 0 : lastNodeRunTimestamp.toJSDate(), status: newStatus, }); const iRunData = { data: executionData, finished: false, mode: executionEntry.mode, waitTill: (_d = executionEntry.waitTill) !== null && _d !== void 0 ? _d : undefined, startedAt: executionEntry.startedAt, stoppedAt: lastNodeRunTimestamp === null || lastNodeRunTimestamp === void 0 ? void 0 : lastNodeRunTimestamp.toJSDate(), status: newStatus, }; const workflowHooks = (0, WorkflowExecuteAdditionalData_1.getWorkflowHooksMain)({ userId: '', workflowData: executionEntry.workflowData, executionMode: executionEntry.mode, executionData, runData: executionData.resultData.runData, retryOf: executionEntry.retryOf, }, executionId); await workflowHooks.executeHookFunctions('workflowExecuteAfter', [iRunData]); this.push.once('editorUiConnected', async () => { await (0, n8n_workflow_1.sleep)(1000); this.push.broadcast('executionRecovered', { executionId }); }); } return executionData; } return; } }; exports.ExecutionDataRecoveryService = ExecutionDataRecoveryService; exports.ExecutionDataRecoveryService = ExecutionDataRecoveryService = __decorate([ (0, typedi_1.Service)(), __metadata("design:paramtypes", [push_1.Push, execution_repository_1.ExecutionRepository]) ], ExecutionDataRecoveryService); //# sourceMappingURL=executionDataRecovery.service.js.map