From e05f2198d584b5a76bcb2a4be2939562b5bf4b43 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 28 Apr 2023 19:05:49 -0600 Subject: [PATCH] Add explicit timeout to mysql DB queries --- backend/mempool-config.sample.json | 3 +- .../__fixtures__/mempool-config.template.json | 3 +- backend/src/__tests__/config.test.ts | 3 +- backend/src/config.ts | 4 ++- backend/src/database.ts | 28 +++++++++++++++++-- docker/README.md | 1 + docker/backend/mempool-config.json | 3 +- docker/backend/start.sh | 1 + 8 files changed, 39 insertions(+), 7 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 1c7097de4..32becd00d 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -61,7 +61,8 @@ "SOCKET": "/var/run/mysql/mysql.sock", "DATABASE": "mempool", "USERNAME": "mempool", - "PASSWORD": "mempool" + "PASSWORD": "mempool", + "TIMEOUT": 180000 }, "SYSLOG": { "ENABLED": true, diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 6c2269a4f..eb082d89f 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -62,7 +62,8 @@ "PORT": 18, "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", - "PASSWORD": "__DATABASE_PASSWORD__" + "PASSWORD": "__DATABASE_PASSWORD__", + "TIMEOUT": "__DATABASE_TIMEOUT__" }, "SYSLOG": { "ENABLED": false, diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index e12f90a86..aa287308b 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -72,7 +72,8 @@ describe('Mempool Backend Config', () => { PORT: 3306, DATABASE: 'mempool', USERNAME: 'mempool', - PASSWORD: 'mempool' + PASSWORD: 'mempool', + TIMEOUT: 180000, }); expect(config.SYSLOG).toStrictEqual({ diff --git a/backend/src/config.ts b/backend/src/config.ts index 7c0e4e950..ff5ea4f9f 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -86,6 +86,7 @@ interface IConfig { DATABASE: string; USERNAME: string; PASSWORD: string; + TIMEOUT: number; }; SYSLOG: { ENABLED: boolean; @@ -194,7 +195,8 @@ const defaults: IConfig = { 'PORT': 3306, 'DATABASE': 'mempool', 'USERNAME': 'mempool', - 'PASSWORD': 'mempool' + 'PASSWORD': 'mempool', + 'TIMEOUT': 180000, }, 'SYSLOG': { 'ENABLED': true, diff --git a/backend/src/database.ts b/backend/src/database.ts index a504eb0fa..070774c92 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -33,8 +33,32 @@ import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } fr OkPacket[] | ResultSetHeader>(query, params?): Promise<[T, FieldPacket[]]> { this.checkDBFlag(); - const pool = await this.getPool(); - return pool.query(query, params); + let hardTimeout; + if (query?.timeout != null) { + hardTimeout = Math.floor(query.timeout * 1.1); + } else { + hardTimeout = config.DATABASE.TIMEOUT; + } + if (hardTimeout > 0) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error(`DB query failed to return, reject or time out within ${hardTimeout / 1000}s - ${query?.sql?.slice(0, 160) || (typeof(query) === 'string' || query instanceof String ? query?.slice(0, 160) : 'unknown query')}`)); + }, hardTimeout); + + this.getPool().then(pool => { + return pool.query(query, params) as Promise<[T, FieldPacket[]]>; + }).then(result => { + resolve(result); + }).catch(error => { + reject(error); + }).finally(() => { + clearTimeout(timer); + }); + }); + } else { + const pool = await this.getPool(); + return pool.query(query, params); + } } public async checkDbConnection() { diff --git a/docker/README.md b/docker/README.md index ee5ba11c5..b669b37c8 100644 --- a/docker/README.md +++ b/docker/README.md @@ -269,6 +269,7 @@ Corresponding `docker-compose.yml` overrides: DATABASE_DATABASE: "" DATABASE_USERNAME: "" DATABASE_PASSWORD: "" + DATABASE_TIMEOUT: "" ... ``` diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index f4543bd2e..fd8abaf02 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -60,7 +60,8 @@ "PORT": __DATABASE_PORT__, "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", - "PASSWORD": "__DATABASE_PASSWORD__" + "PASSWORD": "__DATABASE_PASSWORD__", + "TIMEOUT": "__DATABASE_TIMEOUT__" }, "SYSLOG": { "ENABLED": __SYSLOG_ENABLED__, diff --git a/docker/backend/start.sh b/docker/backend/start.sh index c6ce8f1e7..a54f16ec6 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -64,6 +64,7 @@ __DATABASE_PORT__=${DATABASE_PORT:=3306} __DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} __DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} __DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} +__DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} # SYSLOG __SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false}