feat: add master code queue manager
This commit is contained in:
+2
-2
@@ -32,7 +32,7 @@ function help(): unknown {
|
||||
{ command: "server stop", description: "Fire-and-forget docker-compose down for the fixed UniDesk stack." },
|
||||
{ command: "server status", description: "Show fixed ports, containers, service health, and public URLs." },
|
||||
{ command: "server logs [--tail-bytes N]", description: "Return bounded tails from file logs and docker logs." },
|
||||
{ command: "server rebuild <backend-core|frontend|provider-gateway|todo-note|code-queue|project-manager|baidu-netdisk|oa-event-flow>", description: "Build first, then serialize, force-recreate, and validate one Compose service." },
|
||||
{ command: "server rebuild <backend-core|frontend|provider-gateway|todo-note|code-queue-mgr|project-manager|baidu-netdisk|oa-event-flow>", description: "Build first, then serialize, force-recreate, and validate one Compose service." },
|
||||
{ command: "provider attach <providerId> [--master-server URL] [--up] [--force]", description: "Generate the minimal external provider-gateway env/compose bundle; only master server URL and provider id are required." },
|
||||
{ command: "ssh <providerId> [ssh-like args...]", description: "Open a Host SSH / WSL SSH maintenance session through the provider-gateway bridge with built-in remote helper tools in PATH." },
|
||||
{ command: "ssh <providerId> apply-patch [tool args...] < patch.diff", description: "Invoke the injected remote apply_patch helper directly over SSH passthrough and stream the patch from local stdin." },
|
||||
@@ -176,7 +176,7 @@ async function main(): Promise<void> {
|
||||
}
|
||||
if (sub === "rebuild") {
|
||||
if (!isRebuildableService(third)) {
|
||||
throw new Error("server rebuild requires one of: backend-core, frontend, provider-gateway, todo-note, code-queue, project-manager, baidu-netdisk, oa-event-flow");
|
||||
throw new Error("server rebuild requires one of: backend-core, frontend, provider-gateway, todo-note, code-queue-mgr, project-manager, baidu-netdisk, oa-event-flow");
|
||||
}
|
||||
emitJson(commandName, rebuildService(config, third));
|
||||
return;
|
||||
|
||||
@@ -29,6 +29,7 @@ const syntaxFiles = [
|
||||
"src/components/microservices/k3sctl-adapter/src/index.ts",
|
||||
"src/components/microservices/mdtodo/src/index.ts",
|
||||
"src/components/microservices/decision-center/src/index.ts",
|
||||
"src/components/microservices/code-queue-mgr/src/index.ts",
|
||||
];
|
||||
|
||||
export interface CheckOptions {
|
||||
@@ -141,6 +142,7 @@ function unifiedLogRotationItem(): CheckItem {
|
||||
"src/components/microservices/baidu-netdisk/src/index.ts",
|
||||
"src/components/microservices/oa-event-flow/src/index.ts",
|
||||
"src/components/microservices/decision-center/src/index.ts",
|
||||
"src/components/microservices/code-queue-mgr/src/index.ts",
|
||||
];
|
||||
const offenders = serviceFiles.flatMap((path) => {
|
||||
const text = readFileSync(rootPath(path), "utf8");
|
||||
@@ -182,6 +184,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
|
||||
fileItem("src/components/microservices/k3sctl-adapter/src/index.ts"),
|
||||
fileItem("src/components/microservices/mdtodo/src/index.ts"),
|
||||
fileItem("src/components/microservices/decision-center/src/index.ts"),
|
||||
fileItem("src/components/microservices/code-queue-mgr/src/index.ts"),
|
||||
fileItem("scripts/src/deploy.ts"),
|
||||
fileItem("scripts/src/e2e.ts"),
|
||||
);
|
||||
|
||||
@@ -67,7 +67,7 @@ export interface UniDeskMicroserviceConfig {
|
||||
timeoutMs: number;
|
||||
};
|
||||
deployment: {
|
||||
mode: "unidesk-direct" | "k3sctl-managed";
|
||||
mode: "unidesk-direct" | "k3sctl-managed" | "internal-sidecar";
|
||||
adapterServiceId?: string;
|
||||
k3sServiceId?: string;
|
||||
namespace?: string;
|
||||
@@ -169,8 +169,8 @@ function microserviceConfig(item: Record<string, unknown>, index: number): UniDe
|
||||
const frontend = asRecord(item.frontend, `${path}.frontend`);
|
||||
const deployment = item.deployment === undefined ? undefined : asRecord(item.deployment, `${path}.deployment`);
|
||||
const deploymentMode = deployment === undefined ? "unidesk-direct" : stringField(deployment, "mode", `${path}.deployment`);
|
||||
if (deploymentMode !== "unidesk-direct" && deploymentMode !== "k3sctl-managed") {
|
||||
throw new Error(`${path}.deployment.mode must be unidesk-direct or k3sctl-managed`);
|
||||
if (deploymentMode !== "unidesk-direct" && deploymentMode !== "k3sctl-managed" && deploymentMode !== "internal-sidecar") {
|
||||
throw new Error(`${path}.deployment.mode must be unidesk-direct, k3sctl-managed, or internal-sidecar`);
|
||||
}
|
||||
return {
|
||||
id: stringField(item, "id", path),
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface ContainerStatus {
|
||||
ports: string;
|
||||
}
|
||||
|
||||
const rebuildableServices = ["backend-core", "frontend", "provider-gateway", "todo-note", "project-manager", "baidu-netdisk", "oa-event-flow"] as const;
|
||||
const rebuildableServices = ["backend-core", "frontend", "provider-gateway", "todo-note", "code-queue-mgr", "project-manager", "baidu-netdisk", "oa-event-flow"] as const;
|
||||
export type RebuildableService = typeof rebuildableServices[number];
|
||||
|
||||
export function isRebuildableService(value: string | undefined): value is RebuildableService {
|
||||
@@ -143,6 +143,8 @@ export function writeComposeEnv(config: UniDeskConfig, freshLogPrefix: boolean):
|
||||
UNIDESK_TODO_NOTE_REMINDER_SCAN_INTERVAL_MS: runtimeSecret("UNIDESK_TODO_NOTE_REMINDER_SCAN_INTERVAL_MS") || "30000",
|
||||
UNIDESK_TODO_NOTE_REMINDER_CLAUDEQQ_TIMEOUT_MS: runtimeSecret("UNIDESK_TODO_NOTE_REMINDER_CLAUDEQQ_TIMEOUT_MS") || "15000",
|
||||
UNIDESK_TODO_NOTE_REMINDER_CLAUDEQQ_SEND_ATTEMPTS: runtimeSecret("UNIDESK_TODO_NOTE_REMINDER_CLAUDEQQ_SEND_ATTEMPTS") || "3",
|
||||
UNIDESK_CODE_QUEUE_MGR_DATABASE_POOL_MAX: runtimeSecret("UNIDESK_CODE_QUEUE_MGR_DATABASE_POOL_MAX") || "2",
|
||||
UNIDESK_CODE_QUEUE_TRACE_DATABASE_POOL_MAX: runtimeSecret("UNIDESK_CODE_QUEUE_TRACE_DATABASE_POOL_MAX") || "1",
|
||||
UNIDESK_CODE_QUEUE_MINIMAX_API_KEY: runtimeSecret("UNIDESK_CODE_QUEUE_MINIMAX_API_KEY") || runtimeSecret("MINIMAX_API_KEY"),
|
||||
UNIDESK_CODE_QUEUE_MINIMAX_MODEL: runtimeSecret("UNIDESK_CODE_QUEUE_MINIMAX_MODEL") || runtimeSecret("MINIMAX_MODEL") || "MiniMax-M2.7",
|
||||
UNIDESK_CODE_QUEUE_MINIMAX_API_BASE: runtimeSecret("UNIDESK_CODE_QUEUE_MINIMAX_API_BASE") || runtimeSecret("MINIMAX_API_BASE") || "https://api.minimaxi.com/v1",
|
||||
@@ -232,11 +234,10 @@ export function rebuildService(config: UniDeskConfig, service: RebuildableServic
|
||||
const watchdogLog = rootPath(".state", "jobs", "compose-rebuild-watchdog.log");
|
||||
const watchdogInnerScript = [
|
||||
"set -euo pipefail",
|
||||
"sleep 20",
|
||||
`cid=$(${shellJoin(listServiceContainersCommand)} || true)`,
|
||||
`if [ -z "$cid" ]; then echo "$(date -Is) compose_rebuild_watchdog_restore service=${service}" >> ${shellQuote(watchdogLog)}; ${shellJoin(restoreCommand)} >> ${shellQuote(watchdogLog)} 2>&1 || true; fi`,
|
||||
].join("\n");
|
||||
const watchdogScript = `set -euo pipefail; ${shellJoin(["flock", "-w", "300", lockPath, "bash", "-lc", watchdogInnerScript])} || true`;
|
||||
const watchdogScript = `set -euo pipefail; sleep 20; ${shellJoin(["flock", "-w", "300", lockPath, "bash", "-lc", watchdogInnerScript])} || true`;
|
||||
const validateScript = [
|
||||
"ready=0",
|
||||
"for attempt in $(seq 1 60); do",
|
||||
@@ -339,7 +340,9 @@ function composeLockedScript(innerScript: string): string {
|
||||
"set -euo pipefail",
|
||||
`mkdir -p ${shellQuote(rootPath(".state", "locks"))}`,
|
||||
`echo ${shellJoin(["compose_lock_wait", lockPath])}`,
|
||||
shellJoin(["flock", lockPath, "bash", "-lc", innerScript]),
|
||||
// Prevent background helpers spawned by the locked script from inheriting
|
||||
// the compose lock fd and blocking later server rebuild jobs.
|
||||
shellJoin(["flock", "-o", lockPath, "bash", "-lc", innerScript]),
|
||||
].join("; ");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user