From 4efcbc593685286837022e5600d81e67f3e0131c Mon Sep 17 00:00:00 2001 From: Tomi Turtiainen <10324676+tomi@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:33:53 +0300 Subject: [PATCH] fix: Show a more user friendly error message if initial Db connection times out (#10682) --- packages/cli/src/databases/config.ts | 6 +++++ packages/cli/src/db.ts | 25 ++++++++++++++++--- .../src/errors/db-connection-timeout-error.ts | 14 +++++++++++ packages/workflow/src/errors/ensure-error.ts | 9 +++++++ packages/workflow/src/errors/index.ts | 2 ++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 packages/workflow/src/errors/db-connection-timeout-error.ts create mode 100644 packages/workflow/src/errors/ensure-error.ts diff --git a/packages/cli/src/databases/config.ts b/packages/cli/src/databases/config.ts index 9c4562d3d6..51c1c43842 100644 --- a/packages/cli/src/databases/config.ts +++ b/packages/cli/src/databases/config.ts @@ -132,3 +132,9 @@ export function getConnectionOptions(): DataSourceOptions { throw new ApplicationError('Database type currently not supported', { extra: { dbType } }); } } + +export function arePostgresOptions( + options: DataSourceOptions, +): options is PostgresConnectionOptions { + return options.type === 'postgres'; +} diff --git a/packages/cli/src/db.ts b/packages/cli/src/db.ts index e032241426..2645865d0b 100644 --- a/packages/cli/src/db.ts +++ b/packages/cli/src/db.ts @@ -3,12 +3,16 @@ import { Container } from 'typedi'; import type { EntityManager } from '@n8n/typeorm'; // eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import import { DataSource as Connection } from '@n8n/typeorm'; -import { ErrorReporterProxy as ErrorReporter } from 'n8n-workflow'; +import { + DbConnectionTimeoutError, + ensureError, + ErrorReporterProxy as ErrorReporter, +} from 'n8n-workflow'; import { inTest } from '@/constants'; import { wrapMigration } from '@/databases/utils/migration-helpers'; import type { Migration } from '@/databases/types'; -import { getConnectionOptions } from '@/databases/config'; +import { getConnectionOptions, arePostgresOptions } from '@/databases/config'; let connection: Connection; @@ -54,7 +58,22 @@ export async function init(): Promise { const connectionOptions = getConnectionOptions(); connection = new Connection(connectionOptions); Container.set(Connection, connection); - await connection.initialize(); + try { + await connection.initialize(); + } catch (e) { + let error = ensureError(e); + if ( + arePostgresOptions(connectionOptions) && + error.message === 'Connection terminated due to connection timeout' + ) { + error = new DbConnectionTimeoutError({ + cause: error, + configuredTimeoutInMs: connectionOptions.connectTimeoutMS!, + }); + } + + throw error; + } connectionState.connected = true; } diff --git a/packages/workflow/src/errors/db-connection-timeout-error.ts b/packages/workflow/src/errors/db-connection-timeout-error.ts new file mode 100644 index 0000000000..901b9d36b7 --- /dev/null +++ b/packages/workflow/src/errors/db-connection-timeout-error.ts @@ -0,0 +1,14 @@ +import { ApplicationError } from './application.error'; + +export type DbConnectionTimeoutErrorOpts = { + configuredTimeoutInMs: number; + cause: Error; +}; + +export class DbConnectionTimeoutError extends ApplicationError { + constructor(opts: DbConnectionTimeoutErrorOpts) { + const numberFormat = Intl.NumberFormat(); + const errorMessage = `Could not establish database connection within the configured timeout of ${numberFormat.format(opts.configuredTimeoutInMs)} ms. Please ensure the database is configured correctly and the server is reachable. You can increase the timeout by setting the 'DB_POSTGRESDB_CONNECTION_TIMEOUT' environment variable.`; + super(errorMessage, { cause: opts.cause }); + } +} diff --git a/packages/workflow/src/errors/ensure-error.ts b/packages/workflow/src/errors/ensure-error.ts new file mode 100644 index 0000000000..331692d6e8 --- /dev/null +++ b/packages/workflow/src/errors/ensure-error.ts @@ -0,0 +1,9 @@ +/** Ensures `error` is an `Error */ +export function ensureError(error: unknown): Error { + return error instanceof Error + ? error + : new Error('Error that was not an instance of Error was thrown', { + // We should never throw anything except something that derives from Error + cause: error, + }); +} diff --git a/packages/workflow/src/errors/index.ts b/packages/workflow/src/errors/index.ts index b48fecb3bc..5dea5b9e6d 100644 --- a/packages/workflow/src/errors/index.ts +++ b/packages/workflow/src/errors/index.ts @@ -16,3 +16,5 @@ export { TriggerCloseError } from './trigger-close.error'; export { NodeError } from './abstract/node.error'; export { ExecutionBaseError } from './abstract/execution-base.error'; export { ExpressionExtensionError } from './expression-extension.error'; +export { DbConnectionTimeoutError } from './db-connection-timeout-error'; +export { ensureError } from './ensure-error';