From ffecbc70048e07215e2863a717e855eeb8f401a2 Mon Sep 17 00:00:00 2001 From: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com> Date: Sun, 8 Aug 2021 12:04:04 +0200 Subject: [PATCH] :bug: Fix db connection check /healthz (#2041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fix db connection check * 👕 fix missing semi * ⏪ Revert ":bug: Hardcode typeorm@0.2.34 as new version makes health-check fail" This reverts commit ddee2ec47ce44c3222cd63e274635cb1ed809879. * :bug: fix health-check in WebhookServer --- packages/cli/package.json | 2 +- packages/cli/src/Server.ts | 20 +++--- packages/cli/src/WebhookServer.ts | 103 +++++++++++++++--------------- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index dae777a687..5a21a9e651 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -120,7 +120,7 @@ "sqlite3": "^5.0.1", "sse-channel": "^3.1.1", "tslib": "1.14.1", - "typeorm": "0.2.34", + "typeorm": "^0.2.30", "winston": "^3.3.3" }, "jest": { diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 0abd3f60f1..d4341ed711 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -466,16 +466,18 @@ class App { // Does very basic health check this.app.get('/healthz', async (req: express.Request, res: express.Response) => { - const connectionManager = getConnectionManager(); + const connection = getConnectionManager().get(); - if (connectionManager.connections.length === 0) { - const error = new ResponseHelper.ResponseError('No Database connection found!', undefined, 503); - return ResponseHelper.sendErrorResponse(res, error); - } - - if (connectionManager.connections[0].isConnected === false) { - // Connection is not active - const error = new ResponseHelper.ResponseError('Database connection not active!', undefined, 503); + try { + if (connection.isConnected === false) { + // Connection is not active + throw new Error('No active database connection!'); + } + // DB ping + await connection.query('SELECT 1'); + } catch (err) { + LoggerProxy.error('No Database connection!', err); + const error = new ResponseHelper.ResponseError('No Database connection!', undefined, 503); return ResponseHelper.sendErrorResponse(res, error); } diff --git a/packages/cli/src/WebhookServer.ts b/packages/cli/src/WebhookServer.ts index becfb71af7..245e3a2504 100644 --- a/packages/cli/src/WebhookServer.ts +++ b/packages/cli/src/WebhookServer.ts @@ -111,7 +111,7 @@ export function registerProductionWebhooks() { } class App { - + app: express.Application; activeWorkflowRunner: ActiveWorkflowRunner.ActiveWorkflowRunner; endpointWebhook: string; @@ -129,12 +129,12 @@ class App { protocol: string; sslKey: string; sslCert: string; - + presetCredentialsLoaded: boolean; - + constructor() { this.app = express(); - + this.endpointWebhook = config.get('endpoints.webhook') as string; this.saveDataErrorExecution = config.get('executions.saveDataOnError') as string; this.saveDataSuccessExecution = config.get('executions.saveDataOnSuccess') as string; @@ -143,22 +143,22 @@ class App { this.maxExecutionTimeout = config.get('executions.maxTimeout') as number; this.timezone = config.get('generic.timezone') as string; this.restEndpoint = config.get('endpoints.rest') as string; - + this.activeWorkflowRunner = ActiveWorkflowRunner.getInstance(); - + this.activeExecutionsInstance = ActiveExecutions.getInstance(); - + this.protocol = config.get('protocol'); this.sslKey = config.get('ssl_key'); this.sslCert = config.get('ssl_cert'); - + this.externalHooks = ExternalHooks(); - + this.presetCredentialsLoaded = false; this.endpointPresetCredentials = config.get('credentials.overwrite.endpoint') as string; } - - + + /** * Returns the current epoch time * @@ -168,15 +168,15 @@ class App { getCurrentDate(): Date { return new Date(); } - - + + async config(): Promise { - + this.versions = await GenericHelpers.getVersions(); - + // Compress the response data this.app.use(compression()); - + // Make sure that each request has the "parsedUrl" parameter this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { (req as ICustomRequest).parsedUrl = parseUrl(req); @@ -184,7 +184,7 @@ class App { req.rawBody = Buffer.from('', 'base64'); next(); }); - + // Support application/json type post data this.app.use(bodyParser.json({ limit: '16mb', verify: (req, res, buf) => { @@ -192,7 +192,7 @@ class App { req.rawBody = buf; }, })); - + // Support application/xml type post data // @ts-ignore this.app.use(bodyParser.xml({ @@ -202,14 +202,14 @@ class App { explicitArray: false, // Only put properties in array if length > 1 }, })); - + this.app.use(bodyParser.text({ limit: '16mb', verify: (req, res, buf) => { // @ts-ignore req.rawBody = buf; }, })); - + //support application/x-www-form-urlencoded post data this.app.use(bodyParser.urlencoded({ extended: false, verify: (req, res, buf) => { @@ -217,7 +217,7 @@ class App { req.rawBody = buf; }, })); - + if (process.env['NODE_ENV'] !== 'production') { this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { // Allow access also from frontend when developing @@ -227,64 +227,65 @@ class App { next(); }); } - - + + this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { if (Db.collections.Workflow === null) { const error = new ResponseHelper.ResponseError('Database is not ready!', undefined, 503); return ResponseHelper.sendErrorResponse(res, error); } - + next(); }); - - - + + + // ---------------------------------------- // Healthcheck // ---------------------------------------- - - + + // Does very basic health check this.app.get('/healthz', async (req: express.Request, res: express.Response) => { - - const connectionManager = getConnectionManager(); - - if (connectionManager.connections.length === 0) { - const error = new ResponseHelper.ResponseError('No Database connection found!', undefined, 503); + + const connection = getConnectionManager().get(); + + try { + if (connection.isConnected === false) { + // Connection is not active + throw new Error('No active database connection!'); + } + // DB ping + await connection.query('SELECT 1'); + } catch (err) { + const error = new ResponseHelper.ResponseError('No Database connection!', undefined, 503); return ResponseHelper.sendErrorResponse(res, error); } - - if (connectionManager.connections[0].isConnected === false) { - // Connection is not active - const error = new ResponseHelper.ResponseError('Database connection not active!', undefined, 503); - return ResponseHelper.sendErrorResponse(res, error); - } - + // Everything fine const responseData = { status: 'ok', }; - + ResponseHelper.sendSuccessResponse(res, responseData, true, 200); }); - + registerProductionWebhooks.apply(this); - + } - + } export async function start(): Promise { const PORT = config.get('port'); const ADDRESS = config.get('listen_address'); - + const app = new App(); - + await app.config(); - + let server; - + if (app.protocol === 'https' && app.sslKey && app.sslCert) { const https = require('https'); const privateKey = readFileSync(app.sslKey, 'utf8'); @@ -295,12 +296,12 @@ export async function start(): Promise { const http = require('http'); server = http.createServer(app.app); } - + server.listen(PORT, ADDRESS, async () => { const versions = await GenericHelpers.getVersions(); console.log(`n8n ready on ${ADDRESS}, port ${PORT}`); console.log(`Version: ${versions.cli}`); - + await app.externalHooks.run('n8n.ready', [app]); }); }