Add option to cycle between multiple postgres instances

This commit is contained in:
Ajay
2022-06-25 01:41:45 -04:00
parent a8d0336cae
commit 1a232600a1
4 changed files with 59 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
import fs from "fs";
import { SBSConfig } from "./types/config.model";
import packageJson from "../package.json";
import { isBoolean, isNumber } from "lodash";
import { isNumber } from "lodash";
const isTestMode = process.env.npm_lifecycle_script === packageJson.scripts.test;
const configFile = process.env.TEST_POSTGRES ? "ci.json"
@@ -81,6 +81,17 @@ addDefaults(config, {
rejectUnauthorized: false
}
},
postgresReadOnly: {
enabled: false,
weight: 1,
user: "",
host: "",
password: "",
port: 5432,
ssl: {
rejectUnauthorized: false
}
},
dumpDatabase: {
enabled: false,
minTimeBetweenMs: 180000,

View File

@@ -3,6 +3,7 @@ import { IDatabase, QueryType } from "./IDatabase";
import { Client, Pool, PoolClient, types } from "pg";
import fs from "fs";
import { CustomPostgresConfig, CustomPostgresReadOnlyConfig } from "../types/config.model";
// return numeric (pg_type oid=1700) as float
types.setTypeParser(1700, function(val) {
@@ -14,16 +15,33 @@ types.setTypeParser(20, function(val) {
return parseInt(val, 10);
});
export interface DatabaseConfig {
dbSchemaFileName: string,
dbSchemaFolder: string,
fileNamePrefix: string,
readOnly: boolean,
createDbIfNotExists: boolean,
postgres: CustomPostgresConfig,
postgresReadOnly: CustomPostgresReadOnlyConfig
}
export class Postgres implements IDatabase {
private pool: Pool;
private poolRead: Pool;
constructor(private config: Record<string, any>) {}
constructor(private config: DatabaseConfig) {}
async init(): Promise<void> {
this.pool = new Pool(this.config.postgres);
this.pool.on("error", (err) => {
const errorHandler = (err: Error) => {
Logger.error(err.stack);
});
};
this.pool.on("error", errorHandler);
if (this.config.postgresReadOnly) {
this.poolRead = new Pool(this.config.postgresReadOnly);
this.poolRead.on("error", errorHandler);
}
if (!this.config.readOnly) {
if (this.config.createDbIfNotExists) {
@@ -60,7 +78,7 @@ export class Postgres implements IDatabase {
let client: PoolClient;
try {
client = await this.pool.connect();
client = await this.getClient(type);
const queryResult = await client.query({ text: query, values: params });
switch (type) {
@@ -85,6 +103,15 @@ export class Postgres implements IDatabase {
}
}
private getClient(type: string): Promise<PoolClient> {
if (this.poolRead && (type === "get" || type === "all")
&& Math.random() > 1 / (this.config.postgresReadOnly.weight + 1)) {
return this.poolRead.connect();
} else {
return this.pool.connect();
}
}
private async createDB() {
const client = new Client({
...this.config.postgres,

View File

@@ -19,7 +19,11 @@ if (config.mysql) {
postgres: {
...config.postgres,
database: "sponsorTimes",
}
},
postgresReadOnly: config.postgresReadOnly ? {
...config.postgresReadOnly,
database: "sponsorTimes"
} : null
});
privateDB = new Postgres({
@@ -31,7 +35,11 @@ if (config.mysql) {
postgres: {
...config.postgres,
database: "privateDB"
}
},
postgresReadOnly: config.postgresReadOnly ? {
...config.postgresReadOnly,
database: "privateDB"
} : null
});
} else {
db = new Sqlite({

View File

@@ -5,10 +5,14 @@ interface RedisConfig extends redis.RedisClientOptions {
enabled: boolean;
}
interface CustomPostgresConfig extends PoolConfig {
export interface CustomPostgresConfig extends PoolConfig {
enabled: boolean;
}
export interface CustomPostgresReadOnlyConfig extends CustomPostgresConfig {
weight: number;
}
export interface SBSConfig {
[index: string]: any
port: number;
@@ -51,6 +55,7 @@ export interface SBSConfig {
redis?: RedisConfig;
maxRewardTimePerSegmentInSeconds?: number;
postgres?: CustomPostgresConfig;
postgresReadOnly?: CustomPostgresReadOnlyConfig;
dumpDatabase?: DumpDatabase;
diskCacheURL: string;
crons: CronJobOptions;