mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 18:41:14 +00:00
feat(core): Add execution runData recovery and status field (#5112)
* adds ExecutionEvents view modal to ExecutionList * fix time rendering and remove wf column * checks for unfinished executions and fails them * prevent re-setting stoppedAt for execution * some cleanup / manually create rundata after crash * quicksave * remove Threads lib, log worker rewrite * cleanup comment * fix sentry destination return value * test for tests... * run tests with single worker * fix tests * remove console log * add endpoint for execution data recovery * lint cleanup and some refactoring * fix accidental recursion * remove cyclic imports * add rundata recovery to Workflowrunner * remove comments * cleanup and refactor * adds a status field to executions * setExecutionStatus on queued worker * fix onWorkflowPostExecute * set waiting from worker * get crashed status into frontend * remove comment * merge fix * cleanup * catch empty rundata in recovery * refactor IExecutionsSummary and inject nodeExecution Errors * reduce default event log size to 10mb from 100mb * add per node execution status * lint fix * merge and lint fix * phrasing change * improve preview rendering and messaging * remove debug * Improve partial rundata recovery * fix labels * fix line through * send manual rundata to ui at crash * some type and msg push fixes * improve recovered item rendering in preview * update workflowStatistics on recover * merge fix * review fixes * merge fix * notify eventbus when ui is back up * add a small timeout to make sure the UI is back up * increase reconnect timeout to 30s * adjust recover timeout and ui connection lost msg * do not stop execution in editor after x reconnects * add executionRecovered push event * fix recovered connection not green * remove reconnect toast and merge existing rundata * merge editor and recovered data for own mode
This commit is contained in:
committed by
GitHub
parent
3a9c257f55
commit
d143f3f2ec
@@ -33,6 +33,7 @@ import type {
|
||||
IWorkflowHooksOptionalParameters,
|
||||
IWorkflowSettings,
|
||||
WorkflowExecuteMode,
|
||||
ExecutionStatus,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
ErrorReporterProxy as ErrorReporter,
|
||||
@@ -335,16 +336,22 @@ function hookFunctionsPush(): IWorkflowExecuteHooks {
|
||||
// Clone the object except the runData. That one is not supposed
|
||||
// to be send. Because that data got send piece by piece after
|
||||
// each node which finished executing
|
||||
const pushRunData = {
|
||||
...fullRunData,
|
||||
data: {
|
||||
...fullRunData.data,
|
||||
resultData: {
|
||||
...fullRunData.data.resultData,
|
||||
runData: {},
|
||||
// Edit: we now DO send the runData to the UI if mode=manual so that it shows the point of crashes
|
||||
let pushRunData;
|
||||
if (fullRunData.mode === 'manual') {
|
||||
pushRunData = fullRunData;
|
||||
} else {
|
||||
pushRunData = {
|
||||
...fullRunData,
|
||||
data: {
|
||||
...fullRunData.data,
|
||||
resultData: {
|
||||
...fullRunData.data.resultData,
|
||||
runData: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Push data to editor-ui once workflow finished
|
||||
Logger.debug(`Save execution progress to database for execution ID ${executionId} `, {
|
||||
@@ -445,6 +452,8 @@ export function hookFunctionsPreExecute(parentProcessMode?: string): IWorkflowEx
|
||||
// Set last executed node so that it may resume on failure
|
||||
fullExecutionData.data.resultData.lastNodeExecuted = nodeName;
|
||||
|
||||
fullExecutionData.status = 'running';
|
||||
|
||||
const flattenedExecutionData = ResponseHelper.flattenExecutionData(fullExecutionData);
|
||||
|
||||
await Db.collections.Execution.update(
|
||||
@@ -600,6 +609,7 @@ function hookFunctionsSave(parentProcessMode?: string): IWorkflowExecuteHooks {
|
||||
stoppedAt: fullRunData.stoppedAt,
|
||||
workflowData: pristineWorkflowData,
|
||||
waitTill: fullRunData.waitTill,
|
||||
status: fullRunData.status,
|
||||
};
|
||||
|
||||
if (this.retryOf !== undefined) {
|
||||
@@ -711,7 +721,11 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks {
|
||||
}
|
||||
}
|
||||
|
||||
const workflowDidSucceed = !fullRunData.data.resultData.error;
|
||||
const workflowHasCrashed = fullRunData.status === 'crashed';
|
||||
const workflowDidSucceed = !fullRunData.data.resultData.error && !workflowHasCrashed;
|
||||
let workflowStatusFinal: ExecutionStatus = workflowDidSucceed ? 'success' : 'failed';
|
||||
if (workflowHasCrashed) workflowStatusFinal = 'crashed';
|
||||
|
||||
if (!workflowDidSucceed) {
|
||||
executeErrorWorkflow(
|
||||
this.workflowData,
|
||||
@@ -730,6 +744,7 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks {
|
||||
stoppedAt: fullRunData.stoppedAt,
|
||||
workflowData: this.workflowData,
|
||||
waitTill: fullRunData.data.waitTill,
|
||||
status: workflowStatusFinal,
|
||||
};
|
||||
|
||||
if (this.retryOf !== undefined) {
|
||||
@@ -749,6 +764,11 @@ function hookFunctionsSaveWorker(): IWorkflowExecuteHooks {
|
||||
executionData as IExecutionFlattedDb,
|
||||
);
|
||||
|
||||
// For reasons(tm) the execution status is not updated correctly in the first update, so has to be written again (tbd)
|
||||
await Db.collections.Execution.update(this.executionId, {
|
||||
status: executionData.status,
|
||||
});
|
||||
|
||||
if (fullRunData.finished === true && this.retryOf !== undefined) {
|
||||
// If the retry was successful save the reference it on the original execution
|
||||
await Db.collections.Execution.update(this.retryOf, {
|
||||
@@ -995,6 +1015,7 @@ async function executeWorkflow(
|
||||
mode: 'integrated',
|
||||
startedAt: new Date(),
|
||||
stoppedAt: new Date(),
|
||||
status: 'error',
|
||||
};
|
||||
// When failing, we might not have finished the execution
|
||||
// Therefore, database might not contain finished errors.
|
||||
@@ -1006,6 +1027,7 @@ async function executeWorkflow(
|
||||
finished: fullRunData.finished ? fullRunData.finished : false,
|
||||
startedAt: fullRunData.startedAt,
|
||||
stoppedAt: fullRunData.stoppedAt,
|
||||
status: fullRunData.status,
|
||||
workflowData,
|
||||
};
|
||||
if (workflowData.id) {
|
||||
@@ -1048,6 +1070,19 @@ async function executeWorkflow(
|
||||
};
|
||||
}
|
||||
|
||||
export function setExecutionStatus(status: ExecutionStatus) {
|
||||
if (this.executionId === undefined) {
|
||||
Logger.debug(`Setting execution status "${status}" failed because executionId is undefined`);
|
||||
return;
|
||||
}
|
||||
Logger.debug(`Setting execution status for ${this.executionId} to "${status}"`);
|
||||
ActiveExecutions.getInstance()
|
||||
.setStatus(this.executionId, status)
|
||||
.catch((error) => {
|
||||
Logger.debug(`Setting execution status "${status}" failed: ${error.message}`);
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function sendMessageToUI(source: string, messages: any[]) {
|
||||
const { sessionId } = this;
|
||||
@@ -1101,6 +1136,7 @@ export async function getBase(
|
||||
currentNodeParameters,
|
||||
executionTimeoutTimestamp,
|
||||
userId,
|
||||
setExecutionStatus,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user