UNPKG

@clickup/pg-mig

Version:

PostgreSQL schema migration tool with microsharding and clustering support

86 lines 3.67 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; } get workers() { return this._workers; } get totalMigrations() { return this._totalMigrations; } get processedMigrations() { let num = 0; for (const worker of this.workers) { num += worker.succeededMigrations + worker.errorMigrations.length; } return num; } get elapsedSeconds() { return (Date.now() - this._startTime) / 1000; } get numErrors() { let num = 0; for (const worker of this._workers) { if (worker.errorMigrations.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.numErrors) { 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.name()); 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.numErrors) { return false; } // All done. return this.numErrors === 0; } } exports.Grid = Grid; //# sourceMappingURL=Grid.js.map