@clickup/pg-mig
Version:
PostgreSQL schema migration tool with microsharding and clustering support
111 lines • 4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Worker = void 0;
const async_rwlock_1 = require("async-rwlock");
const await_semaphore_1 = require("await-semaphore");
const promiseAllMap_1 = require("./helpers/promiseAllMap");
const rwLock = new async_rwlock_1.RWLock();
class Worker {
constructor(chainsQueue, semaphores) {
this.chainsQueue = chainsQueue;
this.semaphores = semaphores;
this._succeededMigrations = 0;
this._errorMigrations = [];
this._warningMigrations = [];
this._curDest = null;
this._curMigration = null;
this._curLine = null;
}
get succeededMigrations() {
return this._succeededMigrations;
}
get errorMigrations() {
return this._errorMigrations;
}
get warningMigrations() {
return this._warningMigrations;
}
get curDest() {
return this._curDest;
}
get curMigration() {
return this._curMigration;
}
get curLine() {
return this._curLine;
}
async run(onChange) {
while (this.chainsQueue.length > 0) {
const chain = this.chainsQueue.shift();
for (const migration of chain.migrations) {
this._curDest = chain.dest;
this._curMigration = migration;
this._curLine = null;
onChange();
const interval = setInterval(() => onChange(), 200); // for long-running migrations
try {
const { warning } = await this.processMigration(chain.dest, migration);
this._succeededMigrations++;
if (warning) {
this._warningMigrations.push({
dest: chain.dest,
migration,
payload: warning,
});
}
}
catch (error) {
this._errorMigrations.push({
dest: chain.dest,
migration,
payload: error,
});
break;
}
finally {
clearInterval(interval);
onChange();
}
}
}
this._curDest = null;
this._curMigration = null;
this._curLine = null;
onChange();
}
async processMigration(dest, migration) {
this._curLine = "waiting to satisfy parallelism limits...";
const releases = await (0, promiseAllMap_1.promiseAllMap)([
migration.file.runAlone
? rwLock.writeLock().then(() => rwLock.unlock.bind(rwLock))
: rwLock.readLock().then(() => rwLock.unlock.bind(rwLock)),
this.acquireSemaphore(migration.file.parallelismGlobal, migration.version),
this.acquireSemaphore(migration.file.parallelismPerHost, dest.host + ":" + migration.version),
], async (p) => p);
try {
this._curLine = null;
const res = await dest.runFile(migration.file.fileName, migration.newVersions, (proc) => {
this._curLine = proc.lastOutLine;
});
if (res.code) {
throw res.out.trimEnd();
}
if (migration.file.delay > 0) {
await new Promise((resolve) => setTimeout(resolve, migration.file.delay));
}
return { warning: res.warning };
}
finally {
releases.forEach((release) => release());
}
}
async acquireSemaphore(maxWorkers, key) {
let semaphore = this.semaphores[key];
if (!semaphore) {
semaphore = this.semaphores[key] = new await_semaphore_1.Semaphore(maxWorkers);
}
return semaphore.acquire();
}
}
exports.Worker = Worker;
//# sourceMappingURL=Worker.js.map