Files
boss/src/demo.ts
2026-03-23 13:17:11 +08:00

131 lines
2.9 KiB
TypeScript

import { spawn, type ChildProcess } from "node:child_process";
import { setTimeout as delay } from "node:timers/promises";
const children: ChildProcess[] = [];
function run(command: string, args: string[]) {
const child = spawn(command, args, {
stdio: "inherit",
shell: false,
env: {
...process.env,
PORT: process.env.PORT ?? "43210",
BOSS_DATA_FILE: process.env.BOSS_DATA_FILE ?? ".boss-data/demo-store.json",
},
});
child.on("exit", (code, signal) => {
console.log(`[demo] child exited`, { code, signal, command, args: args.join(" ") });
if (code && code !== 0 && signal !== "SIGINT" && signal !== "SIGTERM") {
shutdown("SIGTERM");
}
});
children.push(child);
return child;
}
async function waitForHealth(url: string) {
for (let attempt = 0; attempt < 30; attempt += 1) {
try {
const response = await fetch(`${url}/api/health`);
if (response.ok) {
return;
}
} catch {
// wait and retry
}
await delay(1_000);
}
throw new Error(`Server did not become healthy: ${url}`);
}
async function isHealthy(url: string) {
try {
const response = await fetch(`${url}/api/health`);
if (!response.ok) {
return false;
}
const payload = await response.json();
return payload?.status === "ok";
} catch {
return false;
}
}
function shutdown(signal: NodeJS.Signals) {
for (const child of children) {
if (!child.killed) {
child.kill(signal);
}
}
process.exit(0);
}
async function main() {
const serverUrl = `http://127.0.0.1:${process.env.PORT ?? "43210"}`;
const hasExisting = await isHealthy(serverUrl);
if (!hasExisting) {
run(process.execPath, ["./node_modules/tsx/dist/cli.mjs", "src/server.ts"]);
await waitForHealth(serverUrl);
} else {
console.log(`Boss server already running at ${serverUrl}, reusing it.`);
}
run(process.execPath, [
"./node_modules/tsx/dist/cli.mjs",
"src/worker.ts",
"--name",
"win-a",
"--os",
"windows",
"--capability",
"terminal",
"--capability",
"browser",
"--server",
serverUrl,
]);
run(process.execPath, [
"./node_modules/tsx/dist/cli.mjs",
"src/worker.ts",
"--name",
"win-b",
"--os",
"windows",
"--capability",
"terminal",
"--capability",
"test",
"--server",
serverUrl,
]);
run(process.execPath, [
"./node_modules/tsx/dist/cli.mjs",
"src/worker.ts",
"--name",
"mac-a",
"--os",
"macos",
"--capability",
"terminal",
"--capability",
"browser",
"--capability",
"test",
"--server",
serverUrl,
]);
console.log(`Boss demo running at ${serverUrl}`);
console.log("Press Ctrl+C to stop server and workers.");
await new Promise(() => {});
}
process.on("SIGINT", () => shutdown("SIGINT"));
process.on("SIGTERM", () => shutdown("SIGTERM"));
main().catch((error) => {
console.error(error);
shutdown("SIGTERM");
});