Files
pikasTech-HWLAB/web/hwlab-cloud-web/scripts/tasktree-native-supervisor.ts
T

71 lines
3.0 KiB
TypeScript

import { closeSync, mkdirSync, openSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
const webRoot = process.cwd();
const repoRoot = resolve(webRoot, "../..");
const stateDir = resolve(webRoot, ".state/tasktree-native");
const databaseEnvFile = process.env.TASKTREE_NATIVE_DATABASE_ENV_FILE;
const temporalAddress = process.env.TASKTREE_TEMPORAL_ADDRESS;
if (!databaseEnvFile) throw new Error("TASKTREE_NATIVE_DATABASE_ENV_FILE is required");
if (!temporalAddress) throw new Error("TASKTREE_TEMPORAL_ADDRESS is required");
function readEnvValue(path: string, key: string): string {
const line = readFileSync(path, "utf8")
.split(/\r?\n/u)
.find((candidate) => candidate.startsWith(`${key}=`));
if (!line) throw new Error(`${key} is missing from the configured env source`);
const raw = line.slice(key.length + 1).trim();
if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) return raw.slice(1, -1);
return raw;
}
mkdirSync(stateDir, { recursive: true });
const logFd = openSync(resolve(stateDir, "services.log"), "a");
const databaseUrl = readEnvValue(databaseEnvFile, "DATABASE_URL");
const commonEnv = {
...process.env,
TASKTREE_DATABASE_URL: databaseUrl,
TASKTREE_TEMPORAL_ADDRESS: temporalAddress,
TASKTREE_TEMPORAL_NAMESPACE: process.env.TASKTREE_TEMPORAL_NAMESPACE ?? "unidesk",
TASKTREE_TEMPORAL_TASK_QUEUE: process.env.TASKTREE_TEMPORAL_TASK_QUEUE ?? "hwlab-v03-tasktree"
};
const backupWorktree = process.env.TASKTREE_BACKUP_WORKTREE;
const children = [
Bun.spawn([process.execPath, "cmd/hwlab-tasktree-worker/main.ts"], { cwd: repoRoot, env: commonEnv, stdin: "ignore", stdout: logFd, stderr: logFd }),
Bun.spawn([process.execPath, "cmd/hwlab-tasktree-api/main.ts"], {
cwd: repoRoot,
env: {
...commonEnv,
...(backupWorktree ? { TASKTREE_BACKUP_WORKTREE: `${backupWorktree}-api` } : {}),
TASKTREE_API_HOST: "127.0.0.1",
TASKTREE_API_PORT: "6673"
},
stdin: "ignore",
stdout: logFd,
stderr: logFd
}),
Bun.spawn([process.execPath, "x", "vite", "--config", "scripts/tasktree-native-vite.config.ts"], { cwd: webRoot, env: { ...process.env, HWLAB_TASKTREE_NATIVE_API_URL: "http://127.0.0.1:6673" }, stdin: "ignore", stdout: logFd, stderr: logFd })
];
process.stdout.write(`${JSON.stringify({ serviceId: "hwlab-tasktree-native", status: "started", pids: children.map((child) => child.pid), valuesPrinted: false })}\n`);
let stopping = false;
async function stop(): Promise<void> {
if (stopping) return;
stopping = true;
for (const child of children) child.kill("SIGTERM");
await Promise.allSettled(children.map((child) => child.exited));
closeSync(logFd);
process.exit(0);
}
process.once("SIGINT", stop);
process.once("SIGTERM", stop);
const exited = await Promise.race(children.map(async (child, index) => ({ index, code: await child.exited })));
if (!stopping) {
process.stderr.write(`${JSON.stringify({ serviceId: "hwlab-tasktree-native", status: "child-exited", ...exited })}\n`);
await stop();
}