Skip to content

Commit

Permalink
fix(Postgres Trigger Node): closeFunction errors should not prevent…
Browse files Browse the repository at this point in the history
… a workflow from being deactivated (#8738)
  • Loading branch information
netroy committed Mar 5, 2024
1 parent 177d70e commit 7535203
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 25 deletions.
10 changes: 10 additions & 0 deletions packages/core/src/ActiveWorkflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import type {
} from 'n8n-workflow';
import {
ApplicationError,
ErrorReporterProxy as ErrorReporter,
LoggerProxy as Logger,
toCronExpression,
TriggerCloseError,
WorkflowActivationError,
WorkflowDeactivationError,
} from 'n8n-workflow';
Expand Down Expand Up @@ -238,6 +240,14 @@ export class ActiveWorkflows {
try {
await response.closeFunction();
} 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}`);

throw new WorkflowDeactivationError(
Expand Down
57 changes: 33 additions & 24 deletions packages/nodes-base/nodes/Postgres/PostgresTrigger.node.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
NodeOperationError,
TriggerCloseError,
type IDataObject,
type INodeType,
type INodeTypeDescription,
Expand Down Expand Up @@ -257,33 +257,42 @@ export class PostgresTrigger implements INodeType {

const cleanUpDb = async () => {
try {
await connection.none('UNLISTEN $1:name', [pgNames.channelName]);
if (triggerMode === 'createTrigger') {
const functionName = pgNames.functionName.includes('(')
? pgNames.functionName.split('(')[0]
: pgNames.functionName;
await connection.any('DROP FUNCTION IF EXISTS $1:name CASCADE', [functionName]);
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 {
await connection.none('UNLISTEN $1:name', [pgNames.channelName]);
if (triggerMode === 'createTrigger') {
const functionName = pgNames.functionName.includes('(')
? pgNames.functionName.split('(')[0]
: pgNames.functionName;
await connection.any('DROP FUNCTION IF EXISTS $1:name CASCADE', [functionName]);

const schema = this.getNodeParameter('schema', undefined, {
extractValue: true,
}) as string;
const table = this.getNodeParameter('tableName', undefined, {
extractValue: true,
}) as string;
const schema = this.getNodeParameter('schema', undefined, {
extractValue: true,
}) as string;
const table = this.getNodeParameter('tableName', undefined, {
extractValue: true,
}) as string;

await connection.any('DROP TRIGGER IF EXISTS $1:name ON $2:name.$3:name CASCADE', [
pgNames.triggerName,
schema,
table,
]);
await connection.any('DROP TRIGGER IF EXISTS $1:name ON $2:name.$3:name CASCADE', [
pgNames.triggerName,
schema,
table,
]);
}
} catch (error) {
// eslint-disable-next-line n8n-nodes-base/node-execute-block-wrong-error-thrown
throw new TriggerCloseError(this.getNode(), { cause: error as Error, level: 'error' });
}
connection.client.removeListener('notification', onNotification);
} catch (error) {
throw new NodeOperationError(
this.getNode(),
`Postgres Trigger Error: ${(error as Error).message}`,
);
} finally {
connection.client.removeListener('notification', onNotification);
if (!db.$pool.ending) await db.$pool.end();
}
};
Expand Down
2 changes: 1 addition & 1 deletion packages/workflow/src/errors/application.error.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import callsites from 'callsites';
import type { Event } from '@sentry/node';

type Level = 'warning' | 'error' | 'fatal' | 'info';
export type Level = 'warning' | 'error' | 'fatal' | 'info';

export type ReportingOptions = {
level?: Level;
Expand Down
1 change: 1 addition & 0 deletions packages/workflow/src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { WorkflowDeactivationError } from './workflow-deactivation.error';
export { WorkflowOperationError } from './workflow-operation.error';
export { SubworkflowOperationError } from './subworkflow-operation.error';
export { CliWorkflowOperationError } from './cli-subworkflow-operation.error';
export { TriggerCloseError } from './trigger-close.error';

export { NodeError } from './abstract/node.error';
export { ExecutionBaseError } from './abstract/execution-base.error';
Expand Down
16 changes: 16 additions & 0 deletions packages/workflow/src/errors/trigger-close.error.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit 7535203

Please sign in to comment.