fix: Show a more user friendly error message if initial Db connection times out (#10682)

This commit is contained in:
Tomi Turtiainen 2024-09-06 11:33:53 +03:00 committed by GitHub
parent 08abaf9eb2
commit 4efcbc5936
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 53 additions and 3 deletions

View file

@ -132,3 +132,9 @@ export function getConnectionOptions(): DataSourceOptions {
throw new ApplicationError('Database type currently not supported', { extra: { dbType } }); throw new ApplicationError('Database type currently not supported', { extra: { dbType } });
} }
} }
export function arePostgresOptions(
options: DataSourceOptions,
): options is PostgresConnectionOptions {
return options.type === 'postgres';
}

View file

@ -3,12 +3,16 @@ import { Container } from 'typedi';
import type { EntityManager } from '@n8n/typeorm'; import type { EntityManager } from '@n8n/typeorm';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import // eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { DataSource as Connection } from '@n8n/typeorm'; 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 { inTest } from '@/constants';
import { wrapMigration } from '@/databases/utils/migration-helpers'; import { wrapMigration } from '@/databases/utils/migration-helpers';
import type { Migration } from '@/databases/types'; import type { Migration } from '@/databases/types';
import { getConnectionOptions } from '@/databases/config'; import { getConnectionOptions, arePostgresOptions } from '@/databases/config';
let connection: Connection; let connection: Connection;
@ -54,7 +58,22 @@ export async function init(): Promise<void> {
const connectionOptions = getConnectionOptions(); const connectionOptions = getConnectionOptions();
connection = new Connection(connectionOptions); connection = new Connection(connectionOptions);
Container.set(Connection, connection); 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; connectionState.connected = true;
} }

View file

@ -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 });
}
}

View file

@ -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,
});
}

View file

@ -16,3 +16,5 @@ 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';
export { ExpressionExtensionError } from './expression-extension.error'; export { ExpressionExtensionError } from './expression-extension.error';
export { DbConnectionTimeoutError } from './db-connection-timeout-error';
export { ensureError } from './ensure-error';