UNPKG

@clickup/pg-mig

Version:

PostgreSQL schema migration tool with microsharding and clustering support

87 lines 3.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Grid = void 0; const groupBy_1 = __importDefault(require("lodash/groupBy")); const sum_1 = __importDefault(require("lodash/sum")); const promiseAllMap_1 = require("./helpers/promiseAllMap"); const Worker_1 = require("./Worker"); /** * A fixed set of Workers running the migration chains. */ class Grid { constructor(chains, workersPerHost, beforeChains = [], afterChains = []) { this.chains = chains; this.workersPerHost = workersPerHost; this.beforeChains = beforeChains; this.afterChains = afterChains; this.workers = []; this.totalMigrations = 0; this.startTime = 0; } getWorkers() { return this.workers; } getTotalMigrations() { return this.totalMigrations; } getProcessedMigrations() { let num = 0; for (const worker of this.workers) { num += worker.getSucceededMigrations() + worker.getErrorMigrations().length; } return num; } getElapsedSeconds() { return (Date.now() - this.startTime) / 1000; } getNumErrors() { let num = 0; for (const worker of this.workers) { if (worker.getErrorMigrations().length > 0) { num++; } } return num; } async run(onChange = () => { }) { this.startTime = Date.now(); // "Before" sequence. Runs in parallel on all hosts (even on those that // don't have any new migration versions). If we fail, don't even start the // migrations. this.workers.push(...this.beforeChains.map((chain) => new Worker_1.Worker([chain], {}))); await (0, promiseAllMap_1.promiseAllMap)(this.workers, async (worker) => worker.run(onChange)); if (this.getNumErrors()) { return false; } // Main migration. Create up to workersPerHost workers for each host; all // the workers will run in parallel and apply migration chains to various // shards until there is no more chains in the queue. const semaphores = {}; const chainsByDest = (0, groupBy_1.default)(this.chains, (entry) => entry.dest.getName()); for (const chainsQueue of Object.values(chainsByDest)) { // For each one host, start as many workers as independent chains we have // in chainsQueue, but not more than this.workersPerHost. Each worker will // pick up jobs (chains) from the shared chainsQueue then. for (let i = 0; i < Math.min(chainsQueue.length, this.workersPerHost); i++) { this.workers.push(new Worker_1.Worker(chainsQueue, semaphores)); } this.totalMigrations += (0, sum_1.default)(chainsQueue.map((entry) => entry.migrations.length)); } await (0, promiseAllMap_1.promiseAllMap)(this.workers, async (worker) => worker.run(onChange)); // "After" sequence (we run it even on errors above). Runs on all hosts. We // don't clear this._workers here: we want to keep the history of errors. this.workers.push(...this.afterChains.map((chain) => new Worker_1.Worker([chain], {}))); await (0, promiseAllMap_1.promiseAllMap)(this.workers, async (worker) => worker.run(onChange)); if (this.getNumErrors()) { return false; } // All done. return this.getNumErrors() === 0; } } exports.Grid = Grid; //# sourceMappingURL=Grid.js.map