diff --git a/charts/hedera-mirror/templates/secret-passwords.yaml b/charts/hedera-mirror/templates/secret-passwords.yaml index 20e26f3e42d..b8807f1eafe 100644 --- a/charts/hedera-mirror/templates/secret-passwords.yaml +++ b/charts/hedera-mirror/templates/secret-passwords.yaml @@ -50,6 +50,7 @@ stringData: HEDERA_MIRROR_REST_DB_HOST: "{{ $dbHost }}" HEDERA_MIRROR_REST_DB_NAME: "{{ $dbName }}" HEDERA_MIRROR_REST_DB_PASSWORD: "{{ $restPassword }}" + HEDERA_MIRROR_REST_DB_PRIMARYHOST: "{{ ternary $dbHostPrimary $dbHost .Values.stackgres.enabled }}" HEDERA_MIRROR_REST_DB_USERNAME: "{{ $restUsername }}" HEDERA_MIRROR_RESTJAVA_DB_HOST: "{{ $dbHost }}" HEDERA_MIRROR_RESTJAVA_DB_NAME: "{{ $dbName }}" diff --git a/docs/configuration.md b/docs/configuration.md index dcbdc9bc3cf..71d0b1f794d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -519,6 +519,7 @@ value, it is recommended to only populate overridden properties in the custom `a | `hedera.mirror.rest.db.pool.maxConnections` | 10 | The maximum number of clients the database pool can contain | | `hedera.mirror.rest.db.pool.statementTimeout` | 20000 | The number of milliseconds to wait before timing out a query statement | | `hedera.mirror.rest.db.port` | 5432 | The port used to connect to the database | +| `hedera.mirror.rest.db.primaryHost` | "" | Optional IP or hostname used to connect to the primary instance | | `hedera.mirror.rest.db.sslMode` | DISABLE | The ssl level of protection against Eavesdropping, Man-in-the-middle (MITM) and Impersonation on the db connection. Accepts either DISABLE, ALLOW, PREFER, REQUIRE, VERIFY_CA or VERIFY_FULL. | | `hedera.mirror.rest.db.tls.ca` | "" | The path to the certificate authority used by the database for secure connections | | `hedera.mirror.rest.db.tls.cert` | "" | The path to the public key the client should use to securely connect to the database | diff --git a/hedera-mirror-rest/config/application.yml b/hedera-mirror-rest/config/application.yml index 3d8f51036ed..d0ebffe969f 100644 --- a/hedera-mirror-rest/config/application.yml +++ b/hedera-mirror-rest/config/application.yml @@ -13,6 +13,7 @@ hedera: maxSize: 100000 db: host: 127.0.0.1 + primaryHost: "" name: mirror_node password: mirror_api_pass pool: diff --git a/hedera-mirror-rest/server.js b/hedera-mirror-rest/server.js index 91c4a0752bf..1e1a3667bee 100644 --- a/hedera-mirror-rest/server.js +++ b/hedera-mirror-rest/server.js @@ -82,13 +82,27 @@ if (config.db.tls.enabled) { }; } +const primaryPoolConfig = {...poolConfig}; + const Pool = getPoolClass(); const pool = new Pool(poolConfig); + pool.on('error', (error) => { logger.error(`error event emitted on pg pool. ${error.stack}`); }); + global.pool = pool; +if (config.db.primaryHost) { + const primaryPool = new Pool(primaryPoolConfig); + primaryPool.on('error', (error) => { + logger.error(`error event emitted on pg primary pool. ${error.stack}`); + }); + global.primaryPool = primaryPool; +} else { + global.primaryPool = pool; +} + // Express configuration. Prior to v0.5 all sets should be configured before use or they won't be picked up const app = addAsync(express()); const {apiPrefix} = constants; diff --git a/hedera-mirror-rest/service/baseService.js b/hedera-mirror-rest/service/baseService.js index 4b6215f37a3..121b06f0c3d 100644 --- a/hedera-mirror-rest/service/baseService.js +++ b/hedera-mirror-rest/service/baseService.js @@ -65,12 +65,12 @@ class BaseService { }; } - async getRows(query, params) { - return (await pool.queryQuietly(query, params)).rows; + async getRows(query, params, dbPool = pool) { + return (await dbPool.queryQuietly(query, params)).rows; } - async getSingleRow(query, params) { - const rows = await this.getRows(query, params); + async getSingleRow(query, params, dbPool = pool) { + const rows = await this.getRows(query, params, dbPool); if (_.isEmpty(rows) || rows.length > 1) { return null; } diff --git a/hedera-mirror-rest/service/recordFileService.js b/hedera-mirror-rest/service/recordFileService.js index d302134bb74..6e259eeccd9 100644 --- a/hedera-mirror-rest/service/recordFileService.js +++ b/hedera-mirror-rest/service/recordFileService.js @@ -92,7 +92,11 @@ class RecordFileService extends BaseService { * @return {Promise} recordFile subset */ async getRecordFileBlockDetailsFromTimestamp(timestamp) { - const row = await super.getSingleRow(RecordFileService.recordFileBlockDetailsFromTimestampQuery, [timestamp]); + const row = await super.getSingleRow( + RecordFileService.recordFileBlockDetailsFromTimestampQuery, + [timestamp], + primaryPool + ); return _.isNull(row) ? null : new RecordFile(row); } @@ -116,7 +120,7 @@ class RecordFileService extends BaseService { order by consensus_end ${order}`; const params = [timestamps, minTimestamp, BigInt(maxTimestamp) + config.query.maxRecordFileCloseIntervalNs]; - const rows = await super.getRows(query, params); + const rows = await super.getRows(query, params, primaryPool); let index = 0; for (const row of rows) { @@ -145,7 +149,7 @@ class RecordFileService extends BaseService { * @return {Promise} recordFile subset */ async getRecordFileBlockDetailsFromIndex(index) { - const row = await super.getSingleRow(RecordFileService.recordFileBlockDetailsFromIndexQuery, [index]); + const row = await super.getSingleRow(RecordFileService.recordFileBlockDetailsFromIndexQuery, [index], primaryPool); return _.isNull(row) ? null : new RecordFile(row); } @@ -157,7 +161,11 @@ class RecordFileService extends BaseService { * @return {Promise} recordFile subset */ async getRecordFileBlockDetailsFromHash(hash) { - const row = await super.getSingleRow(RecordFileService.recordFileBlockDetailsFromHashQuery, [`${hash}%`]); + const row = await super.getSingleRow( + RecordFileService.recordFileBlockDetailsFromHashQuery, + [`${hash}%`], + primaryPool + ); return _.isNull(row) ? null : new RecordFile(row); } @@ -172,7 +180,8 @@ class RecordFileService extends BaseService { order by ${filters.orderBy} ${filters.order} limit ${filters.limit} `; - const rows = await super.getRows(query, params); + + const rows = await super.getRows(query, params, primaryPool); return rows.map((recordFile) => new RecordFile(recordFile)); } @@ -189,7 +198,7 @@ class RecordFileService extends BaseService { } const query = `${RecordFileService.blocksQuery} where ${whereStatement}`; - const row = await super.getSingleRow(query, params); + const row = await super.getSingleRow(query, params, primaryPool); return row ? new RecordFile(row) : null; }