fix(Postgres Trigger Node): closeFunction errors should not prevent a workflow from being deactivated (#8738)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™ 2024-02-26 14:33:00 +01:00 committed by GitHub
parent 15490ad1d4
commit 7012577fce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 63 additions and 27 deletions

View file

@ -15,8 +15,10 @@ import type {
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import {
ApplicationError, ApplicationError,
ErrorReporterProxy as ErrorReporter,
LoggerProxy as Logger, LoggerProxy as Logger,
toCronExpression, toCronExpression,
TriggerCloseError,
WorkflowActivationError, WorkflowActivationError,
WorkflowDeactivationError, WorkflowDeactivationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
@ -238,6 +240,14 @@ export class ActiveWorkflows {
try { try {
await response.closeFunction(); await response.closeFunction();
} catch (e) { } catch (e) {
if (e instanceof TriggerCloseError) {
Logger.error(
`There was a problem calling "closeFunction" on "${e.node.name}" in workflow "${workflowId}"`,
);
ErrorReporter.error(e, { extra: { target, workflowId } });
return;
}
const error = e instanceof Error ? e : new Error(`${e}`); const error = e instanceof Error ? e : new Error(`${e}`);
throw new WorkflowDeactivationError( throw new WorkflowDeactivationError(

View file

@ -1,5 +1,5 @@
import { import {
NodeOperationError, TriggerCloseError,
type IDataObject, type IDataObject,
type INodeType, type INodeType,
type INodeTypeDescription, type INodeTypeDescription,
@ -256,6 +256,16 @@ export class PostgresTrigger implements INodeType {
await connection.none(`LISTEN ${pgNames.channelName}`); await connection.none(`LISTEN ${pgNames.channelName}`);
const cleanUpDb = async () => { const cleanUpDb = async () => {
try {
try {
// check if the connection is healthy
await connection.query('SELECT 1');
} catch {
// connection already closed. Can't perform cleanup
// eslint-disable-next-line n8n-nodes-base/node-execute-block-wrong-error-thrown
throw new TriggerCloseError(this.getNode(), { level: 'warning' });
}
try { try {
await connection.none('UNLISTEN $1:name', [pgNames.channelName]); await connection.none('UNLISTEN $1:name', [pgNames.channelName]);
if (triggerMode === 'createTrigger') { if (triggerMode === 'createTrigger') {
@ -277,13 +287,12 @@ export class PostgresTrigger implements INodeType {
table, table,
]); ]);
} }
connection.client.removeListener('notification', onNotification);
} catch (error) { } catch (error) {
throw new NodeOperationError( // eslint-disable-next-line n8n-nodes-base/node-execute-block-wrong-error-thrown
this.getNode(), throw new TriggerCloseError(this.getNode(), { cause: error as Error, level: 'error' });
`Postgres Trigger Error: ${(error as Error).message}`, }
);
} finally { } finally {
connection.client.removeListener('notification', onNotification);
if (!db.$pool.ending) await db.$pool.end(); if (!db.$pool.ending) await db.$pool.end();
} }
}; };

View file

@ -1,7 +1,7 @@
import callsites from 'callsites'; import callsites from 'callsites';
import type { Event } from '@sentry/node'; import type { Event } from '@sentry/node';
type Level = 'warning' | 'error' | 'fatal' | 'info'; export type Level = 'warning' | 'error' | 'fatal' | 'info';
export type ReportingOptions = { export type ReportingOptions = {
level?: Level; level?: Level;

View file

@ -10,6 +10,7 @@ export { WorkflowDeactivationError } from './workflow-deactivation.error';
export { WorkflowOperationError } from './workflow-operation.error'; export { WorkflowOperationError } from './workflow-operation.error';
export { SubworkflowOperationError } from './subworkflow-operation.error'; export { SubworkflowOperationError } from './subworkflow-operation.error';
export { CliWorkflowOperationError } from './cli-subworkflow-operation.error'; export { CliWorkflowOperationError } from './cli-subworkflow-operation.error';
export { TriggerCloseError } from './trigger-close.error';
export { NodeError } from './abstract/node.error'; export { NodeError } from './abstract/node.error';
export { ExecutionBaseError } from './abstract/execution-base.error'; export { ExecutionBaseError } from './abstract/execution-base.error';

View file

@ -0,0 +1,16 @@
import type { INode } from '../Interfaces';
import { ApplicationError, type Level } from './application.error';
interface TriggerCloseErrorOptions extends ErrorOptions {
level: Level;
}
export class TriggerCloseError extends ApplicationError {
constructor(
readonly node: INode,
{ cause, level }: TriggerCloseErrorOptions,
) {
super('Trigger Close Failed', { cause, extra: { nodeName: node.name } });
this.level = level;
}
}