From 7dad00523ff53a9ad49730c3421b880bdaecc979 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 28 Aug 2023 19:20:58 +0900 Subject: [PATCH] Implement pid file & checks --- backend/mempool-config.sample.json | 3 ++- backend/src/__tests__/config.test.ts | 1 + backend/src/config.ts | 2 ++ backend/src/database.ts | 29 ++++++++++++++++++++++++++++ backend/src/index.ts | 14 ++++++++++++++ docker/backend/mempool-config.json | 3 ++- docker/backend/start.sh | 2 ++ 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 00fe95cc5..4bbf6cfad 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -68,7 +68,8 @@ "DATABASE": "mempool", "USERNAME": "mempool", "PASSWORD": "mempool", - "TIMEOUT": 180000 + "TIMEOUT": 180000, + "PID_DIR": "" }, "SYSLOG": { "ENABLED": true, diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 8097a2465..1a21cd99b 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -84,6 +84,7 @@ describe('Mempool Backend Config', () => { USERNAME: 'mempool', PASSWORD: 'mempool', TIMEOUT: 180000, + PID_DIR: '' }); expect(config.SYSLOG).toStrictEqual({ diff --git a/backend/src/config.ts b/backend/src/config.ts index ed320d957..9ded762fa 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -93,6 +93,7 @@ interface IConfig { USERNAME: string; PASSWORD: string; TIMEOUT: number; + PID_DIR: string; }; SYSLOG: { ENABLED: boolean; @@ -219,6 +220,7 @@ const defaults: IConfig = { 'USERNAME': 'mempool', 'PASSWORD': 'mempool', 'TIMEOUT': 180000, + 'PID_DIR': '', }, 'SYSLOG': { 'ENABLED': true, diff --git a/backend/src/database.ts b/backend/src/database.ts index 6ad545fda..c27f28d23 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -1,3 +1,5 @@ +import * as fs from 'fs'; +import path from 'path'; import config from './config'; import { createPool, Pool, PoolConnection } from 'mysql2/promise'; import logger from './logger'; @@ -101,6 +103,33 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr } } + public getPidLock(): boolean { + const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); + if (fs.existsSync(filePath)) { + const pid = fs.readFileSync(filePath).toString(); + if (pid !== `${process.pid}`) { + const msg = `Already running on PID ${pid} (or pid file '${filePath}' is stale)`; + logger.err(msg); + throw new Error(msg); + } else { + return true; + } + } else { + fs.writeFileSync(filePath, `${process.pid}`); + return true; + } + } + + public releasePidLock(): void { + const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); + if (fs.existsSync(filePath)) { + const pid = fs.readFileSync(filePath).toString(); + if (pid === `${process.pid}`) { + fs.unlinkSync(filePath); + } + } + } + private async getPool(): Promise { if (this.pool === null) { this.pool = createPool(this.poolConfig); diff --git a/backend/src/index.ts b/backend/src/index.ts index 9d0fa07f5..a8af35d1c 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -91,11 +91,18 @@ class Server { async startServer(worker = false): Promise { logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`); + // Register cleanup listeners for exit events + ['exit', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'unhandledRejection'].forEach(event => { + process.on(event, () => { this.onExit(event); }); + }); + if (config.MEMPOOL.BACKEND === 'esplora') { bitcoinApi.startHealthChecks(); } if (config.DATABASE.ENABLED) { + DB.getPidLock(); + await DB.checkDbConnection(); try { if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests @@ -306,6 +313,13 @@ class Server { this.lastHeapLogTime = now; } } + + onExit(exitEvent): void { + DB.releasePidLock(); + process.exit(0); + } } + + ((): Server => new Server())(); diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index aa084133f..5642b36d3 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -69,7 +69,8 @@ "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", "PASSWORD": "__DATABASE_PASSWORD__", - "TIMEOUT": __DATABASE_TIMEOUT__ + "TIMEOUT": __DATABASE_TIMEOUT__, + "PID_DIR": "__PID_DIR__", }, "SYSLOG": { "ENABLED": __SYSLOG_ENABLED__, diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 1bfb06c24..938a5c26f 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -71,6 +71,7 @@ __DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} __DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} __DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} +__DATABASE_PID_DIR__=${DATABASE_PID_DIR:=""} # SYSLOG __SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false} @@ -209,6 +210,7 @@ sed -i "s!__DATABASE_DATABASE__!${__DATABASE_DATABASE__}!g" mempool-config.json sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json sed -i "s!__DATABASE_TIMEOUT__!${__DATABASE_TIMEOUT__}!g" mempool-config.json +sed -i "s!__DATABASE_PID_DIR__!${__DATABASE_PID_DIR__}!g" mempool-config.json sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json