mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
feat(database): ✨ Implement read replicas for database
This commit is contained in:
parent
c75306c58b
commit
bc0943c569
4 changed files with 106 additions and 19 deletions
|
|
@ -1,11 +1,13 @@
|
|||
import { getLogger } from "@logtape/logtape";
|
||||
import { drizzle } from "drizzle-orm/node-postgres";
|
||||
import chalk from "chalk";
|
||||
import { type NodePgDatabase, drizzle } from "drizzle-orm/node-postgres";
|
||||
import { withReplicas } from "drizzle-orm/pg-core";
|
||||
import { migrate } from "drizzle-orm/postgres-js/migrator";
|
||||
import { Client } from "pg";
|
||||
import { Pool } from "pg";
|
||||
import { config } from "~/packages/config-manager";
|
||||
import * as schema from "./schema";
|
||||
|
||||
export const client = new Client({
|
||||
const primaryDb = new Pool({
|
||||
host: config.database.host,
|
||||
port: Number(config.database.port),
|
||||
user: config.database.username,
|
||||
|
|
@ -13,24 +15,54 @@ export const client = new Client({
|
|||
database: config.database.database,
|
||||
});
|
||||
|
||||
const replicas =
|
||||
config.database.replicas?.map(
|
||||
(replica) =>
|
||||
new Pool({
|
||||
host: replica.host,
|
||||
port: Number(replica.port),
|
||||
user: replica.username,
|
||||
password: replica.password,
|
||||
database: replica.database,
|
||||
}),
|
||||
) ?? [];
|
||||
|
||||
export const db =
|
||||
(replicas.length ?? 0) > 0
|
||||
? withReplicas(
|
||||
drizzle(primaryDb, { schema }),
|
||||
replicas.map((r) => drizzle(r, { schema })) as [
|
||||
NodePgDatabase<typeof schema>,
|
||||
...NodePgDatabase<typeof schema>[],
|
||||
],
|
||||
)
|
||||
: drizzle(primaryDb, { schema });
|
||||
|
||||
export const setupDatabase = async (info = true) => {
|
||||
const logger = getLogger("database");
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
} catch (e) {
|
||||
if (
|
||||
(e as Error).message ===
|
||||
"Client has already been connected. You cannot reuse a client."
|
||||
) {
|
||||
return;
|
||||
for (const dbPool of [primaryDb, ...replicas]) {
|
||||
try {
|
||||
await dbPool.connect();
|
||||
} catch (e) {
|
||||
if (
|
||||
(e as Error).message ===
|
||||
"Client has already been connected. You cannot reuse a client."
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.fatal`${e}`;
|
||||
logger.fatal`Failed to connect to database ${chalk.bold(
|
||||
// Index of the database in the array
|
||||
replicas.indexOf(dbPool) === -1
|
||||
? "primary"
|
||||
: `replica-${replicas.indexOf(dbPool)}`,
|
||||
)}. Please check your configuration.`;
|
||||
|
||||
// Hang until Ctrl+C is pressed
|
||||
await Bun.sleep(Number.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
logger.fatal`${e}`;
|
||||
logger.fatal`Failed to connect to database. Please check your configuration.`;
|
||||
|
||||
// Hang until Ctrl+C is pressed
|
||||
await Bun.sleep(Number.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
// Migrate the database
|
||||
|
|
@ -50,5 +82,3 @@ export const setupDatabase = async (info = true) => {
|
|||
|
||||
info && logger.info`Database migrated`;
|
||||
};
|
||||
|
||||
export const db = drizzle(client, { schema });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue