n8n
Version:
n8n Workflow Automation Tool
180 lines • 9.89 kB
JavaScript
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
;