mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08: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:
parent
07672cce7d
commit
6c41b29ad2
|
@ -57,6 +57,7 @@ import { User } from './databases/entities/User';
|
|||
import { whereClause } from './WorkflowHelpers';
|
||||
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
||||
import * as ActiveExecutions from './ActiveExecutions';
|
||||
import { createErrorExecution } from './GenericHelpers';
|
||||
|
||||
const activeExecutions = ActiveExecutions.getInstance();
|
||||
|
||||
|
@ -650,7 +651,14 @@ export class ActiveWorkflowRunner {
|
|||
activation,
|
||||
);
|
||||
// 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
|
||||
Logger.debug(`Received event to trigger execution for workflow "${workflow.name}"`);
|
||||
WorkflowHelpers.saveStaticData(workflow);
|
||||
|
|
|
@ -8,12 +8,27 @@
|
|||
import express from 'express';
|
||||
import { join as pathJoin } from 'path';
|
||||
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 config from '../config';
|
||||
|
||||
// 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
|
||||
import { Like } from 'typeorm';
|
||||
// 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;
|
||||
|
|
|
@ -163,24 +163,35 @@ export class ActiveWorkflows {
|
|||
|
||||
// Get all the trigger times
|
||||
const cronTimes = (pollTimes.item || []).map(toCronExpression);
|
||||
|
||||
// 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
|
||||
Logger.debug(`Polling trigger initiated for workflow "${workflow.name}"`, {
|
||||
workflowName: workflow.name,
|
||||
workflowId: workflow.id,
|
||||
});
|
||||
const pollResponse = await workflow.runPoll(node, pollFunctions);
|
||||
|
||||
if (pollResponse !== null) {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
pollFunctions.__emit(pollResponse);
|
||||
try {
|
||||
const pollResponse = await workflow.runPoll(node, pollFunctions);
|
||||
|
||||
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
|
||||
await executeTrigger();
|
||||
await executeTrigger(true);
|
||||
|
||||
const timezone = pollFunctions.getTimezone();
|
||||
|
||||
|
|
|
@ -715,7 +715,7 @@ export interface IHookFunctions {
|
|||
}
|
||||
|
||||
export interface IPollFunctions {
|
||||
__emit(data: INodeExecutionData[][]): void;
|
||||
__emit(data: INodeExecutionData[][] | NodeApiError): void;
|
||||
getCredentials(type: string): Promise<ICredentialDataDecryptedObject>;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
|
|
Loading…
Reference in a new issue