From 85f15d49896d876fa3ab84e9fa1846f856851274 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Sat, 2 Apr 2022 17:33:31 +0200 Subject: [PATCH] fix(EmailReadImap Node): Fix issue that crashed process if node was configured wrong (#3079) * :bug: Fix issue that IMAP node can crash n8n * :shirt: Fix lint issue --- packages/cli/src/ActiveWorkflowRunner.ts | 9 +++++++++ packages/core/src/NodeExecuteFunctions.ts | 3 +++ .../nodes/EmailReadImap/EmailReadImap.node.ts | 20 ++++++++++++------- packages/workflow/src/Interfaces.ts | 1 + packages/workflow/src/Workflow.ts | 16 ++++++++++++++- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/ActiveWorkflowRunner.ts b/packages/cli/src/ActiveWorkflowRunner.ts index bc24be4019..f14fb23ab9 100644 --- a/packages/cli/src/ActiveWorkflowRunner.ts +++ b/packages/cli/src/ActiveWorkflowRunner.ts @@ -682,6 +682,15 @@ export class ActiveWorkflowRunner { (error) => console.error(error), ); }; + returnFunctions.emitError = async (error: Error): Promise => { + await this.activeWorkflows?.remove(workflowData.id.toString()); + this.activationErrors[workflowData.id.toString()] = { + time: new Date().getTime(), + error: { + message: error.message, + }, + }; + }; return returnFunctions; }; } diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 1d54de9a11..02c0723438 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -1750,6 +1750,9 @@ export function getExecuteTriggerFunctions( emit: (data: INodeExecutionData[][]): void => { throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!'); }, + emitError: (error: Error): void => { + throw new Error('Overwrite NodeExecuteFunctions.getExecuteTriggerFunctions.emit function!'); + }, async getCredentials(type: string): Promise { return getCredentials(workflow, node, type, additionalData, mode); }, diff --git a/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts b/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts index 3cd39dfb9b..2f1104d3e2 100644 --- a/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts +++ b/packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts @@ -1,13 +1,15 @@ import { ITriggerFunctions } from 'n8n-core'; import { + createDeferredPromise, IBinaryData, IBinaryKeyData, IDataObject, + IDeferredPromise, INodeExecutionData, INodeType, INodeTypeDescription, ITriggerResponse, - LoggerProxy, + LoggerProxy as Logger, NodeOperationError, } from 'n8n-workflow'; @@ -25,10 +27,6 @@ import { import * as lodash from 'lodash'; -import { - LoggerProxy as Logger -} from 'n8n-workflow'; - export class EmailReadImap implements INodeType { description: INodeTypeDescription = { displayName: 'EmailReadImap', @@ -377,6 +375,8 @@ export class EmailReadImap implements INodeType { return newEmails; }; + const returnedPromise: IDeferredPromise | undefined = await createDeferredPromise(); + const establishConnection = (): Promise => { let searchCriteria = [ @@ -425,7 +425,11 @@ export class EmailReadImap implements INodeType { } } catch (error) { Logger.error('Email Read Imap node encountered an error fetching new emails', { error }); - throw error; + // Wait with resolving till the returnedPromise got resolved, else n8n will be unhappy + // if it receives an error before the workflow got activated + returnedPromise.promise().then(() => { + this.emitError(error as Error); + }); } } }, @@ -475,10 +479,12 @@ export class EmailReadImap implements INodeType { await connection.end(); } + // Resolve returned-promise so that waiting errors can be emitted + returnedPromise.resolve(); + return { closeFunction, }; - } } diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 058b471c43..5a0fba9d00 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -683,6 +683,7 @@ export interface ITriggerFunctions { data: INodeExecutionData[][], responsePromise?: IDeferredPromise, ): void; + emitError(error: Error, responsePromise?: IDeferredPromise): void; getCredentials(type: string): Promise; getMode(): WorkflowExecuteMode; getActivationMode(): WorkflowActivateMode; diff --git a/packages/workflow/src/Workflow.ts b/packages/workflow/src/Workflow.ts index db696ab9fd..adcee421bc 100644 --- a/packages/workflow/src/Workflow.ts +++ b/packages/workflow/src/Workflow.ts @@ -949,7 +949,7 @@ export class Workflow { const triggerResponse = await nodeType.trigger.call(triggerFunctions); // Add the manual trigger response which resolves when the first time data got emitted - triggerResponse!.manualTriggerResponse = new Promise((resolve) => { + triggerResponse!.manualTriggerResponse = new Promise((resolve, reject) => { triggerFunctions.emit = ( (resolveEmit) => ( @@ -967,6 +967,20 @@ export class Workflow { resolveEmit(data); } )(resolve); + triggerFunctions.emitError = ( + (rejectEmit) => + (error: Error, responsePromise?: IDeferredPromise) => { + additionalData.hooks!.hookFunctions.sendResponse = [ + async (): Promise => { + if (responsePromise) { + responsePromise.reject(error); + } + }, + ]; + + rejectEmit(error); + } + )(reject); }); return triggerResponse;