screenshot-service/container-pool.js

76 lines
1.7 KiB
JavaScript

const { spawn, spawnSync } = require("child_process");
const { IMAGE_NAME } = require("./docker-args");
const { concurrency } = require("./config.json");
class Container {
constructor() {
this.callbacks = [];
this.ready = false;
this.id = spawnSync(
"docker",
["run", "-d", "-v", `${process.cwd()}/static:/opt/static`, IMAGE_NAME],
{
cwd: process.cwd(),
}
)
.stdout.toString()
.replace("\n", "");
this.output = "";
this.bg_process = spawn("docker", ["logs", "-f", this.id]);
this.bg_process.stdout.on("data", (d) => {
try {
const parsed = JSON.parse(d.toString());
if (parsed.code == "ready") {
this.ready = true;
this.signalReady();
}
} catch (e) {}
this.output += d.toString();
});
}
signalReady() {
this.callbacks.forEach((callback) => callback(this));
}
onReady(callback) {
this.ready ? callback() : this.callbacks.push(callback);
}
async waitReady() {
if (this.ready) {
return;
}
return new Promise((resolve) => {
this.onReady(resolve);
});
}
close() {
spawn("docker", ["rm", "-f", this.id]);
}
}
module.exports = new (class ContainerPool {
constructor(concurrency) {
this.concurrency = concurrency;
this.pool = [];
for (let i = 1; i <= this.concurrency; i++) {
this.generateContainer();
}
}
generateContainer() {
this.pool.push(new Container());
}
getContainer() {
if (!this.pool.length) {
throw new Error("pool is empty, try again!");
}
const container = this.pool.shift(); // get and remove from pool the oldest container
this.generateContainer();
return container;
}
})(concurrency);