UNPKG

@clickup/pg-microsharding

Version:
123 lines (107 loc) 3.64 kB
import { basename } from "path"; import chalk from "chalk"; import compact from "lodash/compact"; import { move } from "../api/move"; import { shellQuote } from "../cli"; import { chooseDsns } from "../internal/chooseDsns"; import { getSchemaName } from "../internal/getSchemaName"; import { isTrueValue } from "../internal/isTrueValue"; import { log, print, stdlog } from "../internal/logging"; import { dsnFromToShort } from "../internal/names"; import { normalizeDsns } from "../internal/normalizeDsns"; import type { Args } from "../internal/parseArgs"; import { isInTmuxSession, runInTmux, tryReattachToTmuxSession, } from "../internal/runInTmux"; /** * Moves a shard from one database to another with no downtime. */ export async function actionMove(args: Args): Promise<boolean> { await tryReattachToTmuxSession(); const dsns = await normalizeDsns(args["dsns"]); let shard: number; if (args["shard"]?.match(/^(\d+)$/)) { shard = parseInt(args["shard"], 10); } else { throw "Please provide --shard, a microshard number to move"; } const [fromDsns, fromWarnings] = chooseDsns({ patterns: compact([args["from"]]), existingDsns: dsns, requireMatch: false, }); if (fromDsns.length === 0) { throw "Please provide --from, source DB DSN, as postgresql://user:pass@host/db?options, or a DSN prefix"; } const [toDsns, toWarnings] = chooseDsns({ patterns: compact([args["to"]]), existingDsns: dsns, requireMatch: false, }); if (toDsns.length === 0) { throw "Please provide --to, destination DB DSN, as postgresql://user:pass@host/db?options, or a DSN prefix"; } const activateOnDestination = isTrueValue(args["activate-on-destination"]); if (activateOnDestination === undefined) { throw "Please provide --activate-on-destination=yes or --activate-on-destination=no"; } const deactivateSQL = String(args["deactivate-sql"] || "") || undefined; const maxReplicationLagSec = Number(args["max-replication-lag-sec"] ?? "") || undefined; const wait = args["wait"]; if (isInTmuxSession()) { const unpipe = stdlog.pipeToNewLogFile(`move-${shard}`); try { log( "$ " + [basename(process.argv[1]), ...process.argv.slice(2)] .map(shellQuote) .join(" "), ); for (const warning of [...fromWarnings, ...toWarnings]) { print(warning); } const schema = await getSchemaName(fromDsns[0], shard); if (!schema) { throw `Can't determine schema name for microshard number ${shard}`; } await move({ schema, fromDsn: fromDsns[0], toDsn: toDsns[0], commitAction: activateOnDestination ? "deactivate-activate" : "rename-to-new", deactivateSQL, maxReplicationLagSec, wait, }); if (!activateOnDestination) { print( "\n" + chalk.yellow( "ATTENTION: the schema has been copied, but NOT activated on the destination. " + "So effectively, it was a dry-run, and the data still lives in the source DB. " + "To activate the schema on the destination and deactivate on the source, run " + "the tool with --activate-on-destination=yes option.", ), ); } } finally { await unpipe(); } } else { await runInTmux([ [ { key: shard.toString(), title: `microshard ${shard} | ${dsnFromToShort(fromDsns[0], toDsns[0])}`, command: process.argv, }, ], ]); } return true; }