Skip to content

Commit

Permalink
fix(EmailReadImap Node): Fix issue that crashed process if node was c…
Browse files Browse the repository at this point in the history
…onfigured wrong (#3079)

* 🐛 Fix issue that IMAP node can crash n8n

* 👕 Fix lint issue
  • Loading branch information
janober authored Apr 2, 2022
1 parent 2c72584 commit 85f15d4
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 8 deletions.
9 changes: 9 additions & 0 deletions packages/cli/src/ActiveWorkflowRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,15 @@ export class ActiveWorkflowRunner {
(error) => console.error(error),
);
};
returnFunctions.emitError = async (error: Error): Promise<void> => {
await this.activeWorkflows?.remove(workflowData.id.toString());
this.activationErrors[workflowData.id.toString()] = {
time: new Date().getTime(),
error: {
message: error.message,
},
};
};
return returnFunctions;
};
}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/NodeExecuteFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ICredentialDataDecryptedObject | undefined> {
return getCredentials(workflow, node, type, additionalData, mode);
},
Expand Down
20 changes: 13 additions & 7 deletions packages/nodes-base/nodes/EmailReadImap/EmailReadImap.node.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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',
Expand Down Expand Up @@ -377,6 +375,8 @@ export class EmailReadImap implements INodeType {
return newEmails;
};

const returnedPromise: IDeferredPromise<void> | undefined = await createDeferredPromise<void>();

const establishConnection = (): Promise<ImapSimple> => {

let searchCriteria = [
Expand Down Expand Up @@ -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);
});
}
}
},
Expand Down Expand Up @@ -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,
};

}
}

Expand Down
1 change: 1 addition & 0 deletions packages/workflow/src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,7 @@ export interface ITriggerFunctions {
data: INodeExecutionData[][],
responsePromise?: IDeferredPromise<IExecuteResponsePromiseData>,
): void;
emitError(error: Error, responsePromise?: IDeferredPromise<IExecuteResponsePromiseData>): void;
getCredentials(type: string): Promise<ICredentialDataDecryptedObject | undefined>;
getMode(): WorkflowExecuteMode;
getActivationMode(): WorkflowActivateMode;
Expand Down
16 changes: 15 additions & 1 deletion packages/workflow/src/Workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
(
Expand All @@ -967,6 +967,20 @@ export class Workflow {
resolveEmit(data);
}
)(resolve);
triggerFunctions.emitError = (
(rejectEmit) =>
(error: Error, responsePromise?: IDeferredPromise<IExecuteResponsePromiseData>) => {
additionalData.hooks!.hookFunctions.sendResponse = [
async (): Promise<void> => {
if (responsePromise) {
responsePromise.reject(error);
}
},
];

rejectEmit(error);
}
)(reject);
});

return triggerResponse;
Expand Down

0 comments on commit 85f15d4

Please sign in to comment.