@clickup/pg-mig
Version:
PostgreSQL schema migration tool with microsharding and clustering support
87 lines • 3.7 kB
JavaScript
"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