ework-web 0.10.100 → 0.10.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/coordination.ts +53 -7
package/package.json
CHANGED
package/src/coordination.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getDB } from "./db";
|
|
2
2
|
import { log } from "./logger";
|
|
3
|
+
import { loadConfig } from "./config";
|
|
3
4
|
|
|
4
5
|
export interface DaemonInfo {
|
|
5
6
|
id: number;
|
|
@@ -19,6 +20,50 @@ export interface DaemonDetail {
|
|
|
19
20
|
|
|
20
21
|
const HEARTBEAT_STALE_MS = 120_000;
|
|
21
22
|
|
|
23
|
+
// Split-UID deployments keep the daemon registry in the daemon's own SQLite
|
|
24
|
+
// DB, unreachable (and table-absent) from the web process — the \{\{d_*\}\}
|
|
25
|
+
// queries then fail and every lookup silently degrades to "no daemons".
|
|
26
|
+
// Fall back to the router's registry API, which holds the same rows and is
|
|
27
|
+
// the natural source of truth when web and daemon share no database.
|
|
28
|
+
interface RouterDaemonRow {
|
|
29
|
+
id: number;
|
|
30
|
+
displayName: string;
|
|
31
|
+
endpoint: string;
|
|
32
|
+
capacity: number;
|
|
33
|
+
lastHeartbeat: string;
|
|
34
|
+
status: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let routerCache: { at: number; rows: RouterDaemonRow[] } | null = null;
|
|
38
|
+
|
|
39
|
+
async function routerDaemons(): Promise<RouterDaemonRow[]> {
|
|
40
|
+
if (routerCache && Date.now() - routerCache.at < 15_000) return routerCache.rows;
|
|
41
|
+
try {
|
|
42
|
+
const cfg = await loadConfig();
|
|
43
|
+
if (!cfg.daemonWebhookUrl) return [];
|
|
44
|
+
const res = await fetch(`${cfg.daemonWebhookUrl.replace(/\/$/, "")}/api/daemons`, {
|
|
45
|
+
signal: AbortSignal.timeout(5000),
|
|
46
|
+
});
|
|
47
|
+
const data = (await res.json()) as { daemons?: Array<Partial<RouterDaemonRow>> };
|
|
48
|
+
const rows: RouterDaemonRow[] = (data.daemons ?? [])
|
|
49
|
+
.filter((d): d is Partial<RouterDaemonRow> & { id: number; endpoint: string } =>
|
|
50
|
+
typeof d.id === "number" && typeof d.endpoint === "string")
|
|
51
|
+
.map((d) => ({
|
|
52
|
+
id: d.id,
|
|
53
|
+
displayName: typeof d.displayName === "string" ? d.displayName : `daemon-${d.id}`,
|
|
54
|
+
endpoint: d.endpoint,
|
|
55
|
+
capacity: typeof d.capacity === "number" ? d.capacity : 0,
|
|
56
|
+
lastHeartbeat: typeof d.lastHeartbeat === "string" ? d.lastHeartbeat : "",
|
|
57
|
+
status: typeof d.status === "string" ? d.status : "unknown",
|
|
58
|
+
}));
|
|
59
|
+
routerCache = { at: Date.now(), rows };
|
|
60
|
+
return rows;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
log.info(`coordination: router registry fallback failed (${e instanceof Error ? e.message : String(e)})`);
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
22
67
|
export async function getActiveDaemons(): Promise<DaemonInfo[]> {
|
|
23
68
|
const stale = new Date(Date.now() - HEARTBEAT_STALE_MS);
|
|
24
69
|
const staleStr = stale.toISOString().slice(0, 19).replace("T", " ");
|
|
@@ -130,19 +175,20 @@ export async function getSessionDaemonMap(): Promise<Map<string, SessionDaemonIn
|
|
|
130
175
|
|
|
131
176
|
export async function resolveDaemonEndpoint(daemonId: number): Promise<string | null> {
|
|
132
177
|
try {
|
|
133
|
-
const
|
|
134
|
-
|
|
178
|
+
const local = await getDB().all<{ internal_endpoint: string }>(
|
|
179
|
+
"SELECT internal_endpoint FROM {{d_daemons}} WHERE id = ? LIMIT 1",
|
|
135
180
|
[daemonId],
|
|
136
181
|
);
|
|
137
|
-
const ep =
|
|
138
|
-
if (
|
|
139
|
-
return ep;
|
|
182
|
+
const ep = local[0]?.internal_endpoint;
|
|
183
|
+
if (ep) return ep;
|
|
140
184
|
} catch (e) {
|
|
141
|
-
log.info(`coordination:
|
|
142
|
-
return null;
|
|
185
|
+
log.info(`coordination: local daemon lookup failed (${e instanceof Error ? e.message : String(e)})`);
|
|
143
186
|
}
|
|
187
|
+
const row = (await routerDaemons()).find((d) => d.id === daemonId);
|
|
188
|
+
return row ? row.endpoint : null;
|
|
144
189
|
}
|
|
145
190
|
|
|
191
|
+
|
|
146
192
|
export interface RunningSessionInfo {
|
|
147
193
|
issueNumber: string;
|
|
148
194
|
sessionId: string;
|