mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(cli): Fix issue with n8n crashing when error in poll method (#4008)
* 🐛 Fix issue with n8n crashing when error in poll method * Remove unnecessary imports and add async property * Remove unnecessary imports * ⚡ Move createErrorExecution to genericHelper * ⚡ Improvements Co-authored-by: Omar Ajoue <krynble@gmail.com>
This commit is contained in:
@@ -57,6 +57,7 @@ import { User } from './databases/entities/User';
|
|||||||
import { whereClause } from './WorkflowHelpers';
|
import { whereClause } from './WorkflowHelpers';
|
||||||
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
||||||
import * as ActiveExecutions from './ActiveExecutions';
|
import * as ActiveExecutions from './ActiveExecutions';
|
||||||
|
import { createErrorExecution } from './GenericHelpers';
|
||||||
|
|
||||||
const activeExecutions = ActiveExecutions.getInstance();
|
const activeExecutions = ActiveExecutions.getInstance();
|
||||||
|
|
||||||
@@ -650,7 +651,14 @@ export class ActiveWorkflowRunner {
|
|||||||
activation,
|
activation,
|
||||||
);
|
);
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
returnFunctions.__emit = (data: INodeExecutionData[][]): void => {
|
returnFunctions.__emit = async (
|
||||||
|
data: INodeExecutionData[][] | ExecutionError,
|
||||||
|
): Promise<void> => {
|
||||||
|
if (data instanceof Error) {
|
||||||
|
await createErrorExecution(data, node, workflowData, workflow, mode);
|
||||||
|
this.executeErrorWorkflow(data, workflowData, mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
Logger.debug(`Received event to trigger execution for workflow "${workflow.name}"`);
|
Logger.debug(`Received event to trigger execution for workflow "${workflow.name}"`);
|
||||||
WorkflowHelpers.saveStaticData(workflow);
|
WorkflowHelpers.saveStaticData(workflow);
|
||||||
|
|||||||
@@ -8,12 +8,27 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { join as pathJoin } from 'path';
|
import { join as pathJoin } from 'path';
|
||||||
import { readFile as fsReadFile } from 'fs/promises';
|
import { readFile as fsReadFile } from 'fs/promises';
|
||||||
import { IDataObject } from 'n8n-workflow';
|
import {
|
||||||
|
ExecutionError,
|
||||||
|
IDataObject,
|
||||||
|
INode,
|
||||||
|
IRunExecutionData,
|
||||||
|
Workflow,
|
||||||
|
WorkflowExecuteMode,
|
||||||
|
} from 'n8n-workflow';
|
||||||
import { validate } from 'class-validator';
|
import { validate } from 'class-validator';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
import { Db, ICredentialsDb, IPackageVersions, ResponseHelper } from '.';
|
import {
|
||||||
|
Db,
|
||||||
|
ICredentialsDb,
|
||||||
|
IExecutionDb,
|
||||||
|
IExecutionFlattedDb,
|
||||||
|
IPackageVersions,
|
||||||
|
IWorkflowDb,
|
||||||
|
ResponseHelper,
|
||||||
|
} from '.';
|
||||||
// eslint-disable-next-line import/order
|
// eslint-disable-next-line import/order
|
||||||
import { Like } from 'typeorm';
|
import { Like } from 'typeorm';
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
@@ -214,4 +229,85 @@ export async function validateEntity(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an error execution
|
||||||
|
*
|
||||||
|
* @param {INode} node
|
||||||
|
* @param {IWorkflowDb} workflowData
|
||||||
|
* @param {Workflow} workflow
|
||||||
|
* @param {WorkflowExecuteMode} mode
|
||||||
|
* @returns
|
||||||
|
* @memberof ActiveWorkflowRunner
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export async function createErrorExecution(
|
||||||
|
error: ExecutionError,
|
||||||
|
node: INode,
|
||||||
|
workflowData: IWorkflowDb,
|
||||||
|
workflow: Workflow,
|
||||||
|
mode: WorkflowExecuteMode,
|
||||||
|
): Promise<void> {
|
||||||
|
const saveDataErrorExecutionDisabled = workflowData?.settings?.saveDataErrorExecution === 'none';
|
||||||
|
|
||||||
|
if (saveDataErrorExecutionDisabled) return;
|
||||||
|
|
||||||
|
const executionData: IRunExecutionData = {
|
||||||
|
startData: {
|
||||||
|
destinationNode: node.name,
|
||||||
|
runNodeFilter: [node.name],
|
||||||
|
},
|
||||||
|
executionData: {
|
||||||
|
contextData: {},
|
||||||
|
nodeExecutionStack: [
|
||||||
|
{
|
||||||
|
node,
|
||||||
|
data: {
|
||||||
|
main: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
json: {},
|
||||||
|
pairedItem: {
|
||||||
|
item: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
source: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
waitingExecution: {},
|
||||||
|
waitingExecutionSource: {},
|
||||||
|
},
|
||||||
|
resultData: {
|
||||||
|
runData: {
|
||||||
|
[node.name]: [
|
||||||
|
{
|
||||||
|
startTime: 0,
|
||||||
|
executionTime: 0,
|
||||||
|
error,
|
||||||
|
source: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
error,
|
||||||
|
lastNodeExecuted: node.name,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fullExecutionData: IExecutionDb = {
|
||||||
|
data: executionData,
|
||||||
|
mode,
|
||||||
|
finished: false,
|
||||||
|
startedAt: new Date(),
|
||||||
|
workflowData,
|
||||||
|
workflowId: workflow.id,
|
||||||
|
stoppedAt: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const execution = ResponseHelper.flattenExecutionData(fullExecutionData);
|
||||||
|
|
||||||
|
await Db.collections.Execution.save(execution as IExecutionFlattedDb);
|
||||||
|
}
|
||||||
|
|
||||||
export const DEFAULT_EXECUTIONS_GET_ALL_LIMIT = 20;
|
export const DEFAULT_EXECUTIONS_GET_ALL_LIMIT = 20;
|
||||||
|
|||||||
@@ -163,24 +163,35 @@ export class ActiveWorkflows {
|
|||||||
|
|
||||||
// Get all the trigger times
|
// Get all the trigger times
|
||||||
const cronTimes = (pollTimes.item || []).map(toCronExpression);
|
const cronTimes = (pollTimes.item || []).map(toCronExpression);
|
||||||
|
|
||||||
// The trigger function to execute when the cron-time got reached
|
// The trigger function to execute when the cron-time got reached
|
||||||
const executeTrigger = async () => {
|
const executeTrigger = async (testingTrigger = false) => {
|
||||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||||
Logger.debug(`Polling trigger initiated for workflow "${workflow.name}"`, {
|
Logger.debug(`Polling trigger initiated for workflow "${workflow.name}"`, {
|
||||||
workflowName: workflow.name,
|
workflowName: workflow.name,
|
||||||
workflowId: workflow.id,
|
workflowId: workflow.id,
|
||||||
});
|
});
|
||||||
const pollResponse = await workflow.runPoll(node, pollFunctions);
|
|
||||||
|
|
||||||
if (pollResponse !== null) {
|
try {
|
||||||
// eslint-disable-next-line no-underscore-dangle
|
const pollResponse = await workflow.runPoll(node, pollFunctions);
|
||||||
pollFunctions.__emit(pollResponse);
|
|
||||||
|
if (pollResponse !== null) {
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
pollFunctions.__emit(pollResponse);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// If the poll function failes in the first activation
|
||||||
|
// throw the error back so we let the user know there is
|
||||||
|
// an issue with the trigger.
|
||||||
|
if (testingTrigger) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-underscore-dangle
|
||||||
|
pollFunctions.__emit(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute the trigger directly to be able to know if it works
|
// Execute the trigger directly to be able to know if it works
|
||||||
await executeTrigger();
|
await executeTrigger(true);
|
||||||
|
|
||||||
const timezone = pollFunctions.getTimezone();
|
const timezone = pollFunctions.getTimezone();
|
||||||
|
|
||||||
|
|||||||
@@ -715,7 +715,7 @@ export interface IHookFunctions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IPollFunctions {
|
export interface IPollFunctions {
|
||||||
__emit(data: INodeExecutionData[][]): void;
|
__emit(data: INodeExecutionData[][] | NodeApiError): void;
|
||||||
getCredentials(type: string): Promise<ICredentialDataDecryptedObject>;
|
getCredentials(type: string): Promise<ICredentialDataDecryptedObject>;
|
||||||
getMode(): WorkflowExecuteMode;
|
getMode(): WorkflowExecuteMode;
|
||||||
getActivationMode(): WorkflowActivateMode;
|
getActivationMode(): WorkflowActivateMode;
|
||||||
|
|||||||
Reference in New Issue
Block a user