import { Pool } from 'pg'; import { Gauge, Metric } from 'prom-client'; import { DbLogger } from '../common'; const createTimeout = (timeoutInMilliSeconds: number): Promise => new Promise((_, reject) => setTimeout( () => reject(new Error('METRIC_COLLECTION_TIMEOUT')), timeoutInMilliSeconds, ), ); /** * Creates a `Gauge` metric with the name `ax_postgres__connectivity` which can be added to a metric Registry. * This metric will have a value of `1` if the Database can be reached via the corresponding Pool (within the given timeout), * or a value of `0` otherwise. * * @param pgPool The Postgres Pool to use for checking the connectivity. The connectivity test will be done at the point of metric collection. * @param pgPoolType The Postgres Pool to check connectivity for. * @param timeoutInMilliSeconds The maximum time the connectivity check will run during metric collection. Defaults to `10000ms`. * @returns A `Gauge` metric with a name `ax_postgres__connectivity`. */ export const createPostgresPoolConnectivityMetric = ( logger: DbLogger, pgPool: Pool, pgPoolType: 'dbOwnerPool' | 'envOwnerPool' | 'loginPool', timeoutInMilliSeconds = 10000, ): Metric => { return new Gauge({ name: `ax_postgres_${pgPoolType}_connectivity`, help: `Connection time from the service to the database via the ${pgPoolType} in milliseconds`, async collect() { try { const startTime = process.hrtime(); await Promise.race([ pgPool.query(`SELECT NOW() AS PostgresPoolConnectivityMetric`), createTimeout(timeoutInMilliSeconds), ]); const duration = process.hrtime(startTime); this.set(duration[1] / 1e6); } catch (error) { if ((error).message === 'METRIC_COLLECTION_TIMEOUT') { logger.error( `A METRIC_COLLECTION_TIMEOUT error occurred while checking connectivity to the database via the ${pgPoolType} with a timeout of ${timeoutInMilliSeconds}ms.`, ); } else { logger.error(error, `METRIC_COLLECTION_ERROR`); } this.set(0); } }, }); };