@rulemetric/cli 0.1.1 → 0.2.0
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/README.md +66 -0
- package/dist/base-command.d.ts.map +1 -1
- package/dist/base-command.js +15 -0
- package/dist/base-command.js.map +1 -1
- package/dist/commands/auth/login.d.ts.map +1 -1
- package/dist/commands/auth/login.js +7 -0
- package/dist/commands/auth/login.js.map +1 -1
- package/dist/commands/crons/list.d.ts +7 -0
- package/dist/commands/crons/list.d.ts.map +1 -0
- package/dist/commands/crons/list.js +24 -0
- package/dist/commands/crons/list.js.map +1 -0
- package/dist/commands/crons/run.d.ts +13 -0
- package/dist/commands/crons/run.d.ts.map +1 -0
- package/dist/commands/crons/run.js +48 -0
- package/dist/commands/crons/run.js.map +1 -0
- package/dist/commands/evals/listen.d.ts +28 -2
- package/dist/commands/evals/listen.d.ts.map +1 -1
- package/dist/commands/evals/listen.js +159 -25
- package/dist/commands/evals/listen.js.map +1 -1
- package/dist/commands/evals/listen.test.d.ts +2 -0
- package/dist/commands/evals/listen.test.d.ts.map +1 -0
- package/dist/commands/evals/listen.test.js +48 -0
- package/dist/commands/evals/listen.test.js.map +1 -0
- package/dist/commands/gateway/ensure.js +1 -1
- package/dist/commands/gateway/ensure.js.map +1 -1
- package/dist/commands/hooks/install.d.ts.map +1 -1
- package/dist/commands/hooks/install.js +40 -3
- package/dist/commands/hooks/install.js.map +1 -1
- package/dist/commands/hooks/run.js +1 -1
- package/dist/commands/hooks/run.js.map +1 -1
- package/dist/commands/hooks/uninstall.d.ts.map +1 -1
- package/dist/commands/hooks/uninstall.js +9 -1
- package/dist/commands/hooks/uninstall.js.map +1 -1
- package/dist/commands/org/current.d.ts +7 -0
- package/dist/commands/org/current.d.ts.map +1 -0
- package/dist/commands/org/current.js +70 -0
- package/dist/commands/org/current.js.map +1 -0
- package/dist/commands/org/list.d.ts +7 -0
- package/dist/commands/org/list.d.ts.map +1 -0
- package/dist/commands/org/list.js +37 -0
- package/dist/commands/org/list.js.map +1 -0
- package/dist/commands/org/switch.d.ts +13 -0
- package/dist/commands/org/switch.d.ts.map +1 -0
- package/dist/commands/org/switch.js +52 -0
- package/dist/commands/org/switch.js.map +1 -0
- package/dist/commands/proxy/restart.d.ts +11 -0
- package/dist/commands/proxy/restart.d.ts.map +1 -0
- package/dist/commands/proxy/restart.js +36 -0
- package/dist/commands/proxy/restart.js.map +1 -0
- package/dist/commands/proxy/start.d.ts.map +1 -1
- package/dist/commands/proxy/start.js +4 -0
- package/dist/commands/proxy/start.js.map +1 -1
- package/dist/commands/service/install.d.ts +16 -0
- package/dist/commands/service/install.d.ts.map +1 -1
- package/dist/commands/service/install.js +145 -6
- package/dist/commands/service/install.js.map +1 -1
- package/dist/commands/service/uninstall.d.ts.map +1 -1
- package/dist/commands/service/uninstall.js +28 -0
- package/dist/commands/service/uninstall.js.map +1 -1
- package/dist/commands/sessions/start.d.ts.map +1 -1
- package/dist/commands/sessions/start.js +5 -0
- package/dist/commands/sessions/start.js.map +1 -1
- package/dist/commands/signals/report.d.ts +10 -0
- package/dist/commands/signals/report.d.ts.map +1 -0
- package/dist/commands/signals/report.js +35 -0
- package/dist/commands/signals/report.js.map +1 -0
- package/dist/commands/signals/report.test.d.ts +2 -0
- package/dist/commands/signals/report.test.d.ts.map +1 -0
- package/dist/commands/signals/report.test.js +65 -0
- package/dist/commands/signals/report.test.js.map +1 -0
- package/dist/commands/skills/export-approved.d.ts +10 -0
- package/dist/commands/skills/export-approved.d.ts.map +1 -0
- package/dist/commands/skills/export-approved.js +31 -0
- package/dist/commands/skills/export-approved.js.map +1 -0
- package/dist/commands/skills/publish.d.ts +17 -0
- package/dist/commands/skills/publish.d.ts.map +1 -0
- package/dist/commands/skills/publish.js +80 -0
- package/dist/commands/skills/publish.js.map +1 -0
- package/dist/commands/skills/update.d.ts +3 -0
- package/dist/commands/skills/update.d.ts.map +1 -1
- package/dist/commands/skills/update.js +17 -6
- package/dist/commands/skills/update.js.map +1 -1
- package/dist/commands/suggestions/accept.d.ts +16 -0
- package/dist/commands/suggestions/accept.d.ts.map +1 -0
- package/dist/commands/suggestions/accept.js +61 -0
- package/dist/commands/suggestions/accept.js.map +1 -0
- package/dist/commands/suggestions/accept.test.d.ts +2 -0
- package/dist/commands/suggestions/accept.test.d.ts.map +1 -0
- package/dist/commands/suggestions/accept.test.js +52 -0
- package/dist/commands/suggestions/accept.test.js.map +1 -0
- package/dist/commands/suggestions/dismiss.d.ts +10 -0
- package/dist/commands/suggestions/dismiss.d.ts.map +1 -0
- package/dist/commands/suggestions/dismiss.js +26 -0
- package/dist/commands/suggestions/dismiss.js.map +1 -0
- package/dist/commands/suggestions/list.d.ts +10 -0
- package/dist/commands/suggestions/list.d.ts.map +1 -0
- package/dist/commands/suggestions/list.js +40 -0
- package/dist/commands/suggestions/list.js.map +1 -0
- package/dist/commands/suggestions/refresh.d.ts +7 -0
- package/dist/commands/suggestions/refresh.d.ts.map +1 -0
- package/dist/commands/suggestions/refresh.js +11 -0
- package/dist/commands/suggestions/refresh.js.map +1 -0
- package/dist/dashboard/Dashboard.d.ts.map +1 -1
- package/dist/dashboard/Dashboard.js +7 -1
- package/dist/dashboard/Dashboard.js.map +1 -1
- package/dist/lib/active-org-refresh.d.ts +22 -0
- package/dist/lib/active-org-refresh.d.ts.map +1 -0
- package/dist/lib/active-org-refresh.js +108 -0
- package/dist/lib/active-org-refresh.js.map +1 -0
- package/dist/lib/active-org-refresh.test.d.ts +2 -0
- package/dist/lib/active-org-refresh.test.d.ts.map +1 -0
- package/dist/lib/active-org-refresh.test.js +190 -0
- package/dist/lib/active-org-refresh.test.js.map +1 -0
- package/dist/lib/active-org.d.ts +43 -0
- package/dist/lib/active-org.d.ts.map +1 -0
- package/dist/lib/active-org.js +96 -0
- package/dist/lib/active-org.js.map +1 -0
- package/dist/lib/active-org.test.d.ts +2 -0
- package/dist/lib/active-org.test.d.ts.map +1 -0
- package/dist/lib/active-org.test.js +147 -0
- package/dist/lib/active-org.test.js.map +1 -0
- package/dist/lib/cron-registry.d.ts +47 -0
- package/dist/lib/cron-registry.d.ts.map +1 -0
- package/dist/lib/cron-registry.js +102 -0
- package/dist/lib/cron-registry.js.map +1 -0
- package/dist/lib/cron-registry.test.d.ts +2 -0
- package/dist/lib/cron-registry.test.d.ts.map +1 -0
- package/dist/lib/cron-registry.test.js +136 -0
- package/dist/lib/cron-registry.test.js.map +1 -0
- package/dist/lib/cron-runner.d.ts +16 -0
- package/dist/lib/cron-runner.d.ts.map +1 -0
- package/dist/lib/cron-runner.js +68 -0
- package/dist/lib/cron-runner.js.map +1 -0
- package/dist/lib/detect-languages.d.ts +7 -0
- package/dist/lib/detect-languages.d.ts.map +1 -0
- package/dist/lib/detect-languages.js +113 -0
- package/dist/lib/detect-languages.js.map +1 -0
- package/dist/lib/detect-languages.test.d.ts +2 -0
- package/dist/lib/detect-languages.test.d.ts.map +1 -0
- package/dist/lib/detect-languages.test.js +29 -0
- package/dist/lib/detect-languages.test.js.map +1 -0
- package/dist/lib/eval-executor.d.ts.map +1 -1
- package/dist/lib/eval-executor.js +5 -2
- package/dist/lib/eval-executor.js.map +1 -1
- package/dist/lib/gateway-entry.js +4 -1
- package/dist/lib/gateway-entry.js.map +1 -1
- package/dist/lib/gateway-lifecycle.d.ts +1 -1
- package/dist/lib/gateway-lifecycle.d.ts.map +1 -1
- package/dist/lib/gateway-lifecycle.js +13 -2
- package/dist/lib/gateway-lifecycle.js.map +1 -1
- package/dist/lib/gateway.d.ts +4 -5
- package/dist/lib/gateway.d.ts.map +1 -1
- package/dist/lib/gateway.js +68 -2
- package/dist/lib/gateway.js.map +1 -1
- package/dist/lib/graphile-worker-runner.d.ts +124 -0
- package/dist/lib/graphile-worker-runner.d.ts.map +1 -0
- package/dist/lib/graphile-worker-runner.js +526 -0
- package/dist/lib/graphile-worker-runner.js.map +1 -0
- package/dist/lib/graphile-worker-runner.test.d.ts +2 -0
- package/dist/lib/graphile-worker-runner.test.d.ts.map +1 -0
- package/dist/lib/graphile-worker-runner.test.js +153 -0
- package/dist/lib/graphile-worker-runner.test.js.map +1 -0
- package/dist/lib/handlers/cron-close-stale-sessions.d.ts +3 -0
- package/dist/lib/handlers/cron-close-stale-sessions.d.ts.map +1 -0
- package/dist/lib/handlers/cron-close-stale-sessions.js +8 -0
- package/dist/lib/handlers/cron-close-stale-sessions.js.map +1 -0
- package/dist/lib/handlers/cron-data-integrity-audit.d.ts +3 -0
- package/dist/lib/handlers/cron-data-integrity-audit.d.ts.map +1 -0
- package/dist/lib/handlers/cron-data-integrity-audit.js +16 -0
- package/dist/lib/handlers/cron-data-integrity-audit.js.map +1 -0
- package/dist/lib/handlers/cron-refresh-skills.d.ts +3 -0
- package/dist/lib/handlers/cron-refresh-skills.d.ts.map +1 -0
- package/dist/lib/handlers/cron-refresh-skills.js +91 -0
- package/dist/lib/handlers/cron-refresh-skills.js.map +1 -0
- package/dist/lib/handlers/cron-refresh-skills.test.d.ts +2 -0
- package/dist/lib/handlers/cron-refresh-skills.test.d.ts.map +1 -0
- package/dist/lib/handlers/cron-refresh-skills.test.js +114 -0
- package/dist/lib/handlers/cron-refresh-skills.test.js.map +1 -0
- package/dist/lib/handlers/cron-regenerate-insights.d.ts +3 -0
- package/dist/lib/handlers/cron-regenerate-insights.d.ts.map +1 -0
- package/dist/lib/handlers/cron-regenerate-insights.js +6 -0
- package/dist/lib/handlers/cron-regenerate-insights.js.map +1 -0
- package/dist/lib/handlers/cron-suggest-instructions.d.ts +3 -0
- package/dist/lib/handlers/cron-suggest-instructions.d.ts.map +1 -0
- package/dist/lib/handlers/cron-suggest-instructions.js +159 -0
- package/dist/lib/handlers/cron-suggest-instructions.js.map +1 -0
- package/dist/lib/handlers/cron-suggest-instructions.test.d.ts +2 -0
- package/dist/lib/handlers/cron-suggest-instructions.test.d.ts.map +1 -0
- package/dist/lib/handlers/cron-suggest-instructions.test.js +80 -0
- package/dist/lib/handlers/cron-suggest-instructions.test.js.map +1 -0
- package/dist/lib/handlers/process-conversation.d.ts +35 -0
- package/dist/lib/handlers/process-conversation.d.ts.map +1 -0
- package/dist/lib/handlers/process-conversation.js +35 -0
- package/dist/lib/handlers/process-conversation.js.map +1 -0
- package/dist/lib/handlers/process-eval.d.ts +32 -0
- package/dist/lib/handlers/process-eval.d.ts.map +1 -0
- package/dist/lib/handlers/process-eval.js +207 -0
- package/dist/lib/handlers/process-eval.js.map +1 -0
- package/dist/lib/handlers/process-insights.d.ts +39 -0
- package/dist/lib/handlers/process-insights.d.ts.map +1 -0
- package/dist/lib/handlers/process-insights.js +300 -0
- package/dist/lib/handlers/process-insights.js.map +1 -0
- package/dist/lib/handlers/process-launch.d.ts +29 -0
- package/dist/lib/handlers/process-launch.d.ts.map +1 -0
- package/dist/lib/handlers/process-launch.js +41 -0
- package/dist/lib/handlers/process-launch.js.map +1 -0
- package/dist/lib/hooks-config.d.ts +28 -4
- package/dist/lib/hooks-config.d.ts.map +1 -1
- package/dist/lib/hooks-config.js +138 -10
- package/dist/lib/hooks-config.js.map +1 -1
- package/dist/lib/llm-client.d.ts.map +1 -1
- package/dist/lib/llm-client.js +149 -16
- package/dist/lib/llm-client.js.map +1 -1
- package/dist/lib/mirror-writer-db.d.ts +12 -0
- package/dist/lib/mirror-writer-db.d.ts.map +1 -0
- package/dist/lib/mirror-writer-db.js +51 -0
- package/dist/lib/mirror-writer-db.js.map +1 -0
- package/dist/lib/mirror-writer.d.ts +35 -0
- package/dist/lib/mirror-writer.d.ts.map +1 -0
- package/dist/lib/mirror-writer.js +27 -0
- package/dist/lib/mirror-writer.js.map +1 -0
- package/dist/lib/mirror-writer.test.d.ts +2 -0
- package/dist/lib/mirror-writer.test.d.ts.map +1 -0
- package/dist/lib/mirror-writer.test.js +47 -0
- package/dist/lib/mirror-writer.test.js.map +1 -0
- package/dist/lib/permanent-job-error.d.ts +17 -0
- package/dist/lib/permanent-job-error.d.ts.map +1 -0
- package/dist/lib/permanent-job-error.js +23 -0
- package/dist/lib/permanent-job-error.js.map +1 -0
- package/dist/lib/permanent-job-error.test.d.ts +2 -0
- package/dist/lib/permanent-job-error.test.d.ts.map +1 -0
- package/dist/lib/permanent-job-error.test.js +29 -0
- package/dist/lib/permanent-job-error.test.js.map +1 -0
- package/dist/lib/version-check.d.ts +11 -0
- package/dist/lib/version-check.d.ts.map +1 -0
- package/dist/lib/version-check.js +106 -0
- package/dist/lib/version-check.js.map +1 -0
- package/oclif.manifest.json +611 -81
- package/package.json +19 -5
- package/dist/commands/insights/sync.d.ts +0 -17
- package/dist/commands/insights/sync.d.ts.map +0 -1
- package/dist/commands/insights/sync.js +0 -477
- package/dist/commands/insights/sync.js.map +0 -1
- package/dist/lib/eval-worker.d.ts +0 -12
- package/dist/lib/eval-worker.d.ts.map +0 -1
- package/dist/lib/eval-worker.js +0 -395
- package/dist/lib/eval-worker.js.map +0 -1
- package/dist/lib/insights-worker.d.ts +0 -10
- package/dist/lib/insights-worker.d.ts.map +0 -1
- package/dist/lib/insights-worker.js +0 -329
- package/dist/lib/insights-worker.js.map +0 -1
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
// apps/cli/src/lib/graphile-worker-runner.ts
|
|
2
|
+
//
|
|
3
|
+
// Central worker orchestration: registers the four task handlers, wires
|
|
4
|
+
// `runner.events` so each lifecycle event (job:start/success/error/failed)
|
|
5
|
+
// translates into a mirror-row update via `applyMirrorUpdate`, and runs an
|
|
6
|
+
// in-process heartbeat that carries `currentJobId` + `lastError` so the
|
|
7
|
+
// dashboard can detect hung workers.
|
|
8
|
+
//
|
|
9
|
+
// The heartbeat is started BEFORE `await run(...)` resolves — this is the
|
|
10
|
+
// cold-start fix from the design doc: a worker that boots but takes a few
|
|
11
|
+
// seconds to claim its first job should still show up as alive in the
|
|
12
|
+
// dashboard during that window.
|
|
13
|
+
//
|
|
14
|
+
// Cron tasks are intentionally absent here — they're added in Tasks 17/18.
|
|
15
|
+
import { execFile } from 'node:child_process';
|
|
16
|
+
import * as fs from 'node:fs';
|
|
17
|
+
import { promisify } from 'node:util';
|
|
18
|
+
const execFileAsync = promisify(execFile);
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
import { run } from 'graphile-worker';
|
|
21
|
+
import postgres from 'postgres';
|
|
22
|
+
import { captureException as sentryCaptureException } from '@rulemetric/telemetry';
|
|
23
|
+
import { apiPost } from './api-client.js';
|
|
24
|
+
import { CRON_REGISTRY, wrapCronWithEnvelope } from './cron-registry.js';
|
|
25
|
+
import { processConversation } from './handlers/process-conversation.js';
|
|
26
|
+
import { processEval } from './handlers/process-eval.js';
|
|
27
|
+
import { processInsights } from './handlers/process-insights.js';
|
|
28
|
+
import { processLaunch } from './handlers/process-launch.js';
|
|
29
|
+
import { jobToMirrorUpdate } from './mirror-writer.js';
|
|
30
|
+
import { applyMirrorUpdate, isMirrorTask } from './mirror-writer-db.js';
|
|
31
|
+
import { isPermanentJobError } from './permanent-job-error.js';
|
|
32
|
+
// Watchdog thresholds. Heartbeat runs every 30s, so 5 consecutive failures =
|
|
33
|
+
// ~2.5 min of API unreachable. The pg-listen threshold is 3 min without a
|
|
34
|
+
// successful LISTEN connection, which is well past graphile-worker's own
|
|
35
|
+
// reconnect backoff (caps around 30s) — so by the time we trip, recovery has
|
|
36
|
+
// genuinely failed rather than just being slow.
|
|
37
|
+
const HEARTBEAT_FAILURE_LIMIT = 5;
|
|
38
|
+
const LISTEN_DEAD_THRESHOLD_MS = 180_000;
|
|
39
|
+
const WATCHDOG_INTERVAL_MS = 30_000;
|
|
40
|
+
/**
|
|
41
|
+
* Pure decision function: given watchdog state and "now", return a fatal
|
|
42
|
+
* reason string if the worker should exit, or null if it's healthy. Extracted
|
|
43
|
+
* so the threshold logic can be unit-tested without booting graphile-worker
|
|
44
|
+
* or stubbing process.exit.
|
|
45
|
+
*/
|
|
46
|
+
export function watchdogVerdict(_state, _now) {
|
|
47
|
+
// No process-exit paths. Both signals previously routed here (heartbeat
|
|
48
|
+
// failure and pg LISTEN dead) fire reliably during Supavisor pool pressure
|
|
49
|
+
// even when the worker itself is healthy — exiting turned transient outages
|
|
50
|
+
// into launchd respawn loops whose replacements stacked sockets onto an
|
|
51
|
+
// already-saturated pooler (EMAXCONN cascade; see scripts/repro-pool-cascade.sh
|
|
52
|
+
// injections C and D). Visibility now comes from three places that don't
|
|
53
|
+
// require suicide: (a) heartbeat `lastError` surfaces both conditions to the
|
|
54
|
+
// dashboard, (b) the server-side mirror reconciler flips stuck mirror rows
|
|
55
|
+
// to `failed` after 60s, (c) `unhandledRejection` swallows known transient
|
|
56
|
+
// pg errors instead of letting Node terminate. Kept as a function so test
|
|
57
|
+
// coverage of "does NOT exit under X" stays explicit.
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Derive a short status string from watchdog state for `lastError` reporting.
|
|
62
|
+
* Returns null when nothing notable; otherwise a human-readable signal the
|
|
63
|
+
* dashboard can surface (e.g. "pg listen has been failing for 240s"). This is
|
|
64
|
+
* the logged-signal replacement for the old exit paths.
|
|
65
|
+
*/
|
|
66
|
+
export function watchdogStatus(state, now) {
|
|
67
|
+
if (state.lastListenErrorAt !== null) {
|
|
68
|
+
const lastGood = state.lastListenSuccessAt ?? 0;
|
|
69
|
+
if (state.lastListenErrorAt > lastGood && now - state.lastListenErrorAt > LISTEN_DEAD_THRESHOLD_MS) {
|
|
70
|
+
return `pg listen has been failing for ${Math.round((now - state.lastListenErrorAt) / 1000)}s`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (state.consecutiveHeartbeatFailures >= HEARTBEAT_FAILURE_LIMIT) {
|
|
74
|
+
return `heartbeat has failed ${state.consecutiveHeartbeatFailures} consecutive times`;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Coerce graphile-worker's `error: unknown` payload into a string for
|
|
80
|
+
* `lastError` reporting. Walks `.cause` so a wrapped pg/graphile error still
|
|
81
|
+
* surfaces its underlying message — important for the unhandledRejection
|
|
82
|
+
* swallow regex, which would otherwise miss errors thrown as
|
|
83
|
+
* `new Error("...", { cause: original })`.
|
|
84
|
+
*/
|
|
85
|
+
function errorMessage(err, depth = 0) {
|
|
86
|
+
if (depth > 4)
|
|
87
|
+
return '';
|
|
88
|
+
if (err instanceof Error) {
|
|
89
|
+
const cause = err.cause;
|
|
90
|
+
return cause !== undefined ? `${err.message} | cause: ${errorMessage(cause, depth + 1)}` : err.message;
|
|
91
|
+
}
|
|
92
|
+
if (typeof err === 'string')
|
|
93
|
+
return err;
|
|
94
|
+
try {
|
|
95
|
+
return JSON.stringify(err);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return String(err);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parse `lsof -i TCP -P -n` output into a count of established sockets to the
|
|
103
|
+
* Supabase pooler, grouped by remote host.
|
|
104
|
+
*
|
|
105
|
+
* Matches BOTH pooler ports: 6543 (transaction mode) and 5432 (session mode).
|
|
106
|
+
* The worker connects through the session pooler — see deriveSessionPoolerUrl
|
|
107
|
+
* in commands/evals/listen.ts — while the API uses the transaction pooler; a
|
|
108
|
+
* counter that matched only :6543 would silently report 0 sockets for every
|
|
109
|
+
* worker. The `->` anchor is load-bearing: it matches the REMOTE port, not a
|
|
110
|
+
* local source port that happens to share those digits.
|
|
111
|
+
*/
|
|
112
|
+
export function parsePoolerSockets(lsofStdout) {
|
|
113
|
+
const byNode = {};
|
|
114
|
+
let total = 0;
|
|
115
|
+
for (const line of lsofStdout.split('\n')) {
|
|
116
|
+
const m = line.match(/->([\d.]+|\[[^\]]+\]):(?:6543|5432)\b/);
|
|
117
|
+
if (m) {
|
|
118
|
+
const host = m[1].replace(/^\[|\]$/g, '');
|
|
119
|
+
byNode[host] = (byNode[host] ?? 0) + 1;
|
|
120
|
+
total += 1;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { total, byNode };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Release stale Graphile job locks owned by this worker's user.
|
|
127
|
+
*
|
|
128
|
+
* The graphile_worker._private_jobs table tracks in-flight jobs via
|
|
129
|
+
* `locked_at`/`locked_by`. When a worker crashes mid-job (SIGKILL, OOM, the
|
|
130
|
+
* 10s graceful-shutdown timeout in evals/listen.ts forcing exit before
|
|
131
|
+
* graphile can release locks) those fields stay populated — and graphile's
|
|
132
|
+
* built-in lock-timeout sweeper only reclaims them after a 4-hour TTL by
|
|
133
|
+
* default. Until that fires, the job is invisible to every worker: it's not
|
|
134
|
+
* `available`, but no one is actually running it.
|
|
135
|
+
*
|
|
136
|
+
* At worker BOOT we know that no jobs belonging to OUR user are legitimately
|
|
137
|
+
* in flight (the previous instance is dead — that's why we're starting). Any
|
|
138
|
+
* lock on a task identifier ending `__<userId>` is therefore stale and safe
|
|
139
|
+
* to clear. We scope by suffix so multiple users on a shared pooler don't
|
|
140
|
+
* accidentally release each other's live locks.
|
|
141
|
+
*
|
|
142
|
+
* Best-effort: a thrown executor error is logged but swallowed. If reclaim
|
|
143
|
+
* fails, graphile's 4h timeout still kicks in eventually, and crippling
|
|
144
|
+
* worker startup over a transient DB hiccup is worse than waiting it out.
|
|
145
|
+
*
|
|
146
|
+
* Returns the count of rows released (0 on error or no-op).
|
|
147
|
+
*/
|
|
148
|
+
export async function reclaimStaleLocks(exec, userId, log) {
|
|
149
|
+
try {
|
|
150
|
+
const rows = await exec(`UPDATE graphile_worker._private_jobs j
|
|
151
|
+
SET locked_at = NULL, locked_by = NULL
|
|
152
|
+
FROM graphile_worker._private_tasks t
|
|
153
|
+
WHERE j.task_id = t.id
|
|
154
|
+
AND t.identifier LIKE $1
|
|
155
|
+
AND j.locked_at IS NOT NULL
|
|
156
|
+
RETURNING j.id, t.identifier`, [`%__${userId}`]);
|
|
157
|
+
if (rows.length > 0) {
|
|
158
|
+
const summary = rows.map((r) => `${r.identifier}#${r.id}`).join(', ');
|
|
159
|
+
log(`[startup] reclaimed ${rows.length} stale lock(s): ${summary}`);
|
|
160
|
+
}
|
|
161
|
+
return rows.length;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
log(`[startup] stale-lock reclaim failed (non-fatal, graphile's 4h timeout will eventually free these): ${err instanceof Error ? err.message : String(err)}`);
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Wrap a typed handler so it conforms to graphile-worker's `Task` shape AND
|
|
170
|
+
* intercepts `PermanentJobError` to skip retry waste.
|
|
171
|
+
*
|
|
172
|
+
* How the skip works: graphile-worker decides retry-vs-permanent-fail by
|
|
173
|
+
* comparing `job.attempts >= job.max_attempts` on the in-memory `Job` object
|
|
174
|
+
* AFTER the handler throws (see graphile-worker dist/worker.js). We mutate
|
|
175
|
+
* `helpers.job.max_attempts` to equal the current attempt count just before
|
|
176
|
+
* re-throwing — that flips the inequality so Graphile emits `job:failed`
|
|
177
|
+
* instead of scheduling another retry. The mutation is purely in JS memory;
|
|
178
|
+
* Graphile uses the in-memory `Job` object for its decision and never re-reads
|
|
179
|
+
* `max_attempts` from the DB on this code path, so a SQL update isn't needed.
|
|
180
|
+
*
|
|
181
|
+
* Exported for use in integration tests that want the same retry-skip behavior
|
|
182
|
+
* the runner applies in production.
|
|
183
|
+
*/
|
|
184
|
+
export function makeTask(handler) {
|
|
185
|
+
return (async (payload, helpers) => {
|
|
186
|
+
try {
|
|
187
|
+
await handler(payload, helpers);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
if (isPermanentJobError(err)) {
|
|
191
|
+
// Mutate the in-memory job so Graphile's post-throw retry-vs-fail
|
|
192
|
+
// check (`job.attempts >= job.max_attempts`) sees us at the cap.
|
|
193
|
+
const job = helpers.job;
|
|
194
|
+
job.max_attempts = job.attempts;
|
|
195
|
+
}
|
|
196
|
+
throw err;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Boot a graphile-worker runner with the four task handlers wired up.
|
|
202
|
+
*
|
|
203
|
+
* Returns a cleanup function that:
|
|
204
|
+
* 1. clears the heartbeat interval
|
|
205
|
+
* 2. fires a final `status: 'shutting_down'` heartbeat so the dashboard
|
|
206
|
+
* can show a clean shutdown rather than a missed-heartbeat timeout
|
|
207
|
+
* 3. awaits `runner.stop()` for graceful drain (in-flight jobs finish)
|
|
208
|
+
*/
|
|
209
|
+
export async function startWorker(options) {
|
|
210
|
+
const { connectionString, log, userId } = options;
|
|
211
|
+
// onFatal kept on the options interface for back-compat with callers/tests,
|
|
212
|
+
// but the runner no longer invokes it. All "fatal" signals are reported via
|
|
213
|
+
// heartbeat lastError and the server-side reconciler instead — see
|
|
214
|
+
// watchdogStatus and the comment on watchdogVerdict.
|
|
215
|
+
void options.onFatal;
|
|
216
|
+
const now = options.now ?? Date.now;
|
|
217
|
+
// Stable worker identity: hostname only, NOT including process.pid. Each
|
|
218
|
+
// PID change (restart, --force install, dev iteration) used to create a
|
|
219
|
+
// fresh row in worker_connections, leaving "ghost" entries forever in the
|
|
220
|
+
// dashboard. The heartbeat endpoint UPSERTs by (userId, workerType,
|
|
221
|
+
// clientName) — so collapsing clientName to hostname means one row per
|
|
222
|
+
// host per workerType, regardless of restart count.
|
|
223
|
+
const workerId = os.hostname();
|
|
224
|
+
// Survive graphile-worker's unhandled rejections. The cron scheduler
|
|
225
|
+
// (graphile-worker/dist/cron.js scheduleCronJobs) and the internal worker's
|
|
226
|
+
// completeJob path can throw `(EMAXCONN)` or `Connection terminated
|
|
227
|
+
// unexpectedly` when the Supavisor pool is briefly saturated. Neither path
|
|
228
|
+
// catches its own throw, so Node's default unhandledRejection behavior
|
|
229
|
+
// terminates the process — turning a 30-second transient into an indefinite
|
|
230
|
+
// launchd-restart loop. Reproduction: scripts/repro-pool-cascade.sh D
|
|
231
|
+
// (150 psql sleeps + API down) produces "Failed to release job ...;
|
|
232
|
+
// committing seppuku\nConnection terminated unexpectedly" without these
|
|
233
|
+
// listeners. With them, graphile-worker logs the error and reschedules.
|
|
234
|
+
const pgErrorPattern = /EMAXCONN|Connection terminated|EAUTHTIMEOUT|ECONNRESET|getaddrinfo/i;
|
|
235
|
+
const onUnhandled = (reason) => {
|
|
236
|
+
const msg = errorMessage(reason);
|
|
237
|
+
if (pgErrorPattern.test(msg)) {
|
|
238
|
+
log(`[recovered] transient pool error swallowed: ${msg.slice(0, 200)}`);
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
// Re-throw non-pool errors via the default behavior so real bugs aren't
|
|
242
|
+
// hidden. Setting exitCode lets the runtime decide.
|
|
243
|
+
log(`unhandledRejection (not pool-related): ${msg}`);
|
|
244
|
+
process.exitCode = 1;
|
|
245
|
+
};
|
|
246
|
+
process.on('unhandledRejection', onUnhandled);
|
|
247
|
+
process.on('uncaughtException', onUnhandled);
|
|
248
|
+
const inFlight = new Map();
|
|
249
|
+
// `lastError` surfaces the most recent error from any job for dashboard
|
|
250
|
+
// display — distinct from the per-job `lastError` stored on the Map
|
|
251
|
+
// entry, which is keyed for cleanup but not currently surfaced.
|
|
252
|
+
let lastError = null;
|
|
253
|
+
const mostRecentEntry = () => {
|
|
254
|
+
let last;
|
|
255
|
+
for (const value of inFlight.values())
|
|
256
|
+
last = value;
|
|
257
|
+
return last;
|
|
258
|
+
};
|
|
259
|
+
const watchdog = {
|
|
260
|
+
consecutiveHeartbeatFailures: 0,
|
|
261
|
+
lastListenSuccessAt: null,
|
|
262
|
+
lastListenErrorAt: null,
|
|
263
|
+
};
|
|
264
|
+
// What this worker can claim. Reported on every heartbeat in
|
|
265
|
+
// `metadata.capabilities` so the API can warn when the set drifts from
|
|
266
|
+
// EXPECTED_WORKER_CAPABILITIES['cli-worker'] (apps/api/src/routes/worker-status.ts).
|
|
267
|
+
// Use bare task kinds, not the user-suffixed task names — the server's
|
|
268
|
+
// expected set is `['eval','insights','launch','conversation']`.
|
|
269
|
+
const CAPABILITIES = ['eval', 'insights', 'launch', 'conversation'];
|
|
270
|
+
// De-dupe advisory log lines: server returns the same advisory on every
|
|
271
|
+
// 30s heartbeat, so log only when the message changes (and re-log on
|
|
272
|
+
// recovery from advisory → no advisory).
|
|
273
|
+
let lastLoggedAdvisoryMessage = null;
|
|
274
|
+
const lsofBin = ['/usr/sbin/lsof', '/usr/bin/lsof', '/bin/lsof'].find((p) => fs.existsSync(p)) ?? 'lsof';
|
|
275
|
+
// Fully async: previously this was execFileSync, which can block the event
|
|
276
|
+
// loop for up to the 3s timeout under fork()/process-table contention —
|
|
277
|
+
// exactly the conditions present during Supavisor pool saturation. Blocking
|
|
278
|
+
// the heartbeat tick on lsof would delay the very heartbeat that's supposed
|
|
279
|
+
// to surface the pool-saturation state. Fire-and-forget: never awaited by
|
|
280
|
+
// sendHeartbeat, errors swallowed, no impact on job processing or watchdog.
|
|
281
|
+
const sendPoolerSelfReport = async () => {
|
|
282
|
+
try {
|
|
283
|
+
const { stdout } = await execFileAsync(lsofBin, ['-a', '-p', String(process.pid), '-i', 'TCP', '-P', '-n'], { encoding: 'utf8', timeout: 3000 });
|
|
284
|
+
const { total, byNode } = parsePoolerSockets(stdout);
|
|
285
|
+
await apiPost('/api/diag/pg-health/self-report', {
|
|
286
|
+
process: process.env.PG_APPLICATION_NAME ?? 'rulemetric-worker',
|
|
287
|
+
pid: process.pid,
|
|
288
|
+
pool_max: Number(process.env.PG_POOL_MAX) || 3,
|
|
289
|
+
pooler_sockets: total,
|
|
290
|
+
pooler_sockets_by_node: byNode,
|
|
291
|
+
}).catch(() => null);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// Swallow: lsof binary missing, timeout, permission denied, etc. all
|
|
295
|
+
// mean "no telemetry this tick" — never block job processing.
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const sendHeartbeat = (status = 'alive') => {
|
|
299
|
+
void sendPoolerSelfReport();
|
|
300
|
+
const entry = mostRecentEntry();
|
|
301
|
+
// Merge watchdog status into lastError so the dashboard surfaces wedge
|
|
302
|
+
// conditions (stuck LISTEN, persistent heartbeat failures) without us
|
|
303
|
+
// having to exit the process. lastError already captures the most recent
|
|
304
|
+
// job-level failure; watchdog status takes precedence when present
|
|
305
|
+
// because it indicates a process-level issue the user should see.
|
|
306
|
+
const wdStatus = watchdogStatus(watchdog, now());
|
|
307
|
+
const reportedError = wdStatus ?? lastError;
|
|
308
|
+
return apiPost('/api/workers/heartbeat', {
|
|
309
|
+
workerType: 'cli-worker',
|
|
310
|
+
clientName: workerId,
|
|
311
|
+
workerVersion: '0.1.0',
|
|
312
|
+
currentJobId: entry?.mirrorId ?? null,
|
|
313
|
+
inFlightCount: inFlight.size,
|
|
314
|
+
lastError: reportedError,
|
|
315
|
+
status,
|
|
316
|
+
metadata: { capabilities: CAPABILITIES },
|
|
317
|
+
}).then((result) => {
|
|
318
|
+
watchdog.consecutiveHeartbeatFailures = 0;
|
|
319
|
+
const advisory = result?.advisory;
|
|
320
|
+
if (advisory) {
|
|
321
|
+
if (advisory.message !== lastLoggedAdvisoryMessage) {
|
|
322
|
+
log(`heartbeat advisory [${advisory.code}]: ${advisory.message}`);
|
|
323
|
+
lastLoggedAdvisoryMessage = advisory.message;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else if (lastLoggedAdvisoryMessage !== null) {
|
|
327
|
+
log('heartbeat advisory cleared');
|
|
328
|
+
lastLoggedAdvisoryMessage = null;
|
|
329
|
+
}
|
|
330
|
+
return result;
|
|
331
|
+
}, (err) => {
|
|
332
|
+
watchdog.consecutiveHeartbeatFailures += 1;
|
|
333
|
+
log(`heartbeat failed: ${errorMessage(err)}`);
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
// Cold-start fix: start the heartbeat BEFORE awaiting run(). If `run()`
|
|
337
|
+
// takes a few seconds to settle (initial schema check, LISTEN setup),
|
|
338
|
+
// the worker still appears alive in the dashboard during that window.
|
|
339
|
+
void sendHeartbeat();
|
|
340
|
+
const heartbeatTimer = setInterval(() => {
|
|
341
|
+
void sendHeartbeat();
|
|
342
|
+
}, 30_000);
|
|
343
|
+
// Tag this pool's connections so they show up distinctly in pg_stat_activity
|
|
344
|
+
// (separate from the postgres-js pool inside getDb()).
|
|
345
|
+
const taggedConnectionString = (() => {
|
|
346
|
+
try {
|
|
347
|
+
const u = new URL(connectionString);
|
|
348
|
+
if (!u.searchParams.has('application_name')) {
|
|
349
|
+
u.searchParams.set('application_name', 'rulemetric-worker-graphile');
|
|
350
|
+
}
|
|
351
|
+
return u.toString();
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return connectionString;
|
|
355
|
+
}
|
|
356
|
+
})();
|
|
357
|
+
const runnerOptions = {
|
|
358
|
+
connectionString: taggedConnectionString,
|
|
359
|
+
// After SIGTERM/SIGINT, graphile-worker waits for in-flight jobs to drain
|
|
360
|
+
// before resolving runner.stop(). With handlers that spawn `claude`
|
|
361
|
+
// subprocesses (insights, cron_suggest_instructions), the drain can take
|
|
362
|
+
// minutes. Cap it at 5s so graphile triggers its forcefulShutdown path
|
|
363
|
+
// and runner.stop() resolves promptly. The outer SIGTERM handler in
|
|
364
|
+
// evals/listen.ts wraps this in a 10s process-level timeout too, so even
|
|
365
|
+
// if graphile's force-abort hangs, the worker dies cleanly.
|
|
366
|
+
gracefulShutdownAbortTimeout: 5_000,
|
|
367
|
+
// PgBouncer transaction-mode (Supabase pooler) doesn't share prepared statements across pooled connections — disable to avoid "prepared statement already exists" crashes.
|
|
368
|
+
noPreparedStatements: true,
|
|
369
|
+
// Cap concurrent jobs across all task types. This replaces the global
|
|
370
|
+
// `processing` flag in the legacy worker — Graphile handles fairness
|
|
371
|
+
// and per-task ordering automatically.
|
|
372
|
+
concurrency: 4,
|
|
373
|
+
// Per-user task names — both work tasks (process_*) AND cron tasks. The
|
|
374
|
+
// Graphile queue is global; the suffix is what makes each laptop only
|
|
375
|
+
// claim its own user's jobs. Cron tasks need the suffix too because
|
|
376
|
+
// cron handlers POST to API endpoints that scope by `c.get('userId')` —
|
|
377
|
+
// an unsuffixed cron would be claimed by whichever worker polls first
|
|
378
|
+
// and would only regenerate THAT user's data, leaving every other user
|
|
379
|
+
// without cron-driven updates. With the suffix, each laptop independently
|
|
380
|
+
// schedules and claims its own user's crons. Cost: a user whose laptop is
|
|
381
|
+
// offline at 4am misses that day's skills refresh until they boot back up.
|
|
382
|
+
taskList: {
|
|
383
|
+
[`process_eval__${userId}`]: makeTask(processEval),
|
|
384
|
+
[`process_insights__${userId}`]: makeTask(processInsights),
|
|
385
|
+
[`process_launch__${userId}`]: makeTask(processLaunch),
|
|
386
|
+
[`process_conversation__${userId}`]: makeTask(processConversation),
|
|
387
|
+
// Wrap each cron in `wrapCronWithEnvelope` so we get a uniform
|
|
388
|
+
// `[cron <name>] start/ok/failed` log envelope on every fire. The
|
|
389
|
+
// per-handler progress lines stay as-is — the envelope just bookends.
|
|
390
|
+
// Added 2026-05-21 after the eight-fix arc made it obvious that
|
|
391
|
+
// half the crons logged ad-hoc start lines and none logged duration.
|
|
392
|
+
...Object.fromEntries(CRON_REGISTRY.map((c) => [`${c.name}__${userId}`, wrapCronWithEnvelope(c.name, c.handler)])),
|
|
393
|
+
},
|
|
394
|
+
// `?jobKey=cron-<task>__<userId>` dedupes cron-scheduled jobs in graphile's
|
|
395
|
+
// queue. Without it, every worker restart / missed scheduling could leave
|
|
396
|
+
// duplicates: we observed 3 simultaneous `cron_refresh_skills` rows with
|
|
397
|
+
// the same run_at, each locked by a different internal-worker slot — they
|
|
398
|
+
// saturated concurrency=4 and starved user-facing launches. With jobKey
|
|
399
|
+
// (and the default jobKeyMode='replace'), a subsequent scheduled fire
|
|
400
|
+
// replaces any existing queued job of the same key instead of accumulating.
|
|
401
|
+
// Diagnosed 2026-05-20.
|
|
402
|
+
crontab: CRON_REGISTRY.map((c) => `${c.schedule} ${c.name}__${userId} ?jobKey=cron-${c.name}__${userId}`).join('\n') + '\n',
|
|
403
|
+
};
|
|
404
|
+
// Reclaim stale locks BEFORE booting the runner. When the previous worker
|
|
405
|
+
// instance dies hard (SIGKILL, OOM, the 10s shutdown-grace timeout in
|
|
406
|
+
// evals/listen.ts forcing exit before graphile released locks) the jobs
|
|
407
|
+
// it was holding stay marked `is_available = false AND locked_at IS NOT NULL`
|
|
408
|
+
// — graphile's built-in lock-timeout reclaim only kicks in after a 4h TTL.
|
|
409
|
+
// We know no jobs of OUR user are legitimately in flight at boot (this
|
|
410
|
+
// process IS the user's worker; the previous one is dead). Scoping by
|
|
411
|
+
// `__<userId>` suffix keeps multi-tenant pools safe.
|
|
412
|
+
// See reclaimStaleLocks() for the SQL + rationale.
|
|
413
|
+
{
|
|
414
|
+
const sql = postgres(taggedConnectionString, { max: 1, prepare: false, idle_timeout: 5 });
|
|
415
|
+
try {
|
|
416
|
+
await reclaimStaleLocks(async (text, params) => (await sql.unsafe(text, params)), userId, log);
|
|
417
|
+
}
|
|
418
|
+
finally {
|
|
419
|
+
await sql.end({ timeout: 5 }).catch(() => { });
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const runner = await run(runnerOptions);
|
|
423
|
+
// Each event listener is fire-and-forget on the mirror write. We don't
|
|
424
|
+
// want a transient API blip to break the worker — `applyMirrorUpdate`
|
|
425
|
+
// already retries once internally, and Graphile's own job state is the
|
|
426
|
+
// source of truth regardless.
|
|
427
|
+
//
|
|
428
|
+
// The in-flight Map is keyed by the Graphile job id (numeric, unique
|
|
429
|
+
// per job) so that concurrent jobs don't trample each other's entries.
|
|
430
|
+
// We re-set on `start` so the most-recent insertion order reflects what
|
|
431
|
+
// started last, and delete on success/failed (terminal states).
|
|
432
|
+
// Cron tasks flow through the same runner.events stream as mirror-backed
|
|
433
|
+
// tasks, but they have no mirror row and no entry in ENDPOINTS — short-
|
|
434
|
+
// circuit so they don't fire bogus `/api/.../undefined/state` requests.
|
|
435
|
+
const onStart = ({ job }) => {
|
|
436
|
+
const payload = job.payload;
|
|
437
|
+
const mirrorId = payload.mirrorId ?? String(job.id);
|
|
438
|
+
inFlight.delete(Number(job.id));
|
|
439
|
+
inFlight.set(Number(job.id), { mirrorId });
|
|
440
|
+
if (!isMirrorTask(job.task_identifier))
|
|
441
|
+
return;
|
|
442
|
+
void applyMirrorUpdate(job.task_identifier, jobToMirrorUpdate('job:start', job), log);
|
|
443
|
+
};
|
|
444
|
+
const onSuccess = ({ job }) => {
|
|
445
|
+
inFlight.delete(Number(job.id));
|
|
446
|
+
if (inFlight.size === 0)
|
|
447
|
+
lastError = null;
|
|
448
|
+
if (!isMirrorTask(job.task_identifier))
|
|
449
|
+
return;
|
|
450
|
+
void applyMirrorUpdate(job.task_identifier, jobToMirrorUpdate('job:success', job), log);
|
|
451
|
+
};
|
|
452
|
+
const onError = ({ job, error }) => {
|
|
453
|
+
// Don't remove from inFlight here — the job may still be in-flight
|
|
454
|
+
// if Graphile decides to retry. We only delete on success/failed.
|
|
455
|
+
const message = errorMessage(error);
|
|
456
|
+
lastError = message;
|
|
457
|
+
const entry = inFlight.get(Number(job.id));
|
|
458
|
+
if (entry)
|
|
459
|
+
entry.lastError = message;
|
|
460
|
+
if (!isMirrorTask(job.task_identifier))
|
|
461
|
+
return;
|
|
462
|
+
void applyMirrorUpdate(job.task_identifier, jobToMirrorUpdate('job:error', job), log);
|
|
463
|
+
};
|
|
464
|
+
const onFailed = ({ job, error }) => {
|
|
465
|
+
inFlight.delete(Number(job.id));
|
|
466
|
+
lastError = errorMessage(error);
|
|
467
|
+
// Forward to Sentry with tags that make dashboard filtering useful.
|
|
468
|
+
// `job:failed` fires only after attempts >= max_attempts, so every event
|
|
469
|
+
// here represents a real terminal failure — exactly the signal we want
|
|
470
|
+
// to alert on. The mirrorId is the row in eval_jobs / insights_jobs /
|
|
471
|
+
// launch_jobs that's about to be flipped to `failed`. Crons have no
|
|
472
|
+
// mirror row; for them `mirrorId` is the graphile job id (best we have).
|
|
473
|
+
const payload = (job.payload ?? {});
|
|
474
|
+
sentryCaptureException(error, {
|
|
475
|
+
tags: {
|
|
476
|
+
taskName: job.task_identifier,
|
|
477
|
+
source: 'graphile-worker',
|
|
478
|
+
},
|
|
479
|
+
extra: {
|
|
480
|
+
graphileJobId: String(job.id),
|
|
481
|
+
mirrorId: payload.mirrorId ?? null,
|
|
482
|
+
attempts: job.attempts,
|
|
483
|
+
maxAttempts: job.max_attempts,
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
if (!isMirrorTask(job.task_identifier))
|
|
487
|
+
return;
|
|
488
|
+
void applyMirrorUpdate(job.task_identifier, jobToMirrorUpdate('job:failed', job), log);
|
|
489
|
+
};
|
|
490
|
+
runner.events.on('job:start', onStart);
|
|
491
|
+
runner.events.on('job:success', onSuccess);
|
|
492
|
+
runner.events.on('job:error', onError);
|
|
493
|
+
runner.events.on('job:failed', onFailed);
|
|
494
|
+
// Watchdog signals — observed during the 2026-05-06 wedge, where the
|
|
495
|
+
// PG pool listener died ("Connection terminated unexpectedly" repeating)
|
|
496
|
+
// and the worker stayed alive but stopped polling for ~9 hours.
|
|
497
|
+
runner.events.on('pool:listen:success', () => {
|
|
498
|
+
watchdog.lastListenSuccessAt = now();
|
|
499
|
+
});
|
|
500
|
+
runner.events.on('pool:listen:error', ({ error }) => {
|
|
501
|
+
watchdog.lastListenErrorAt = now();
|
|
502
|
+
log(`pool:listen:error: ${errorMessage(error)}`);
|
|
503
|
+
});
|
|
504
|
+
// Watchdog tick: previously this called onFatal(reason) → process.exit(1).
|
|
505
|
+
// That path was the cascade root cause — see watchdogVerdict comment. The
|
|
506
|
+
// tick now only logs persistent wedge conditions so they show up in
|
|
507
|
+
// stderr alongside the heartbeat-reported status. Kept as a tick (rather
|
|
508
|
+
// than dropped) because logging on a separate cadence from the 30s
|
|
509
|
+
// heartbeat helps operators see whether a condition is sticky or transient
|
|
510
|
+
// when correlating timestamps.
|
|
511
|
+
const watchdogTimer = setInterval(() => {
|
|
512
|
+
const status = watchdogStatus(watchdog, now());
|
|
513
|
+
if (status)
|
|
514
|
+
log(`[watchdog] ${status}`);
|
|
515
|
+
}, WATCHDOG_INTERVAL_MS);
|
|
516
|
+
log(`Worker ${workerId} listening for user ${userId} jobs (eval, insights, launch, conversation)`);
|
|
517
|
+
return async () => {
|
|
518
|
+
clearInterval(heartbeatTimer);
|
|
519
|
+
clearInterval(watchdogTimer);
|
|
520
|
+
process.off('unhandledRejection', onUnhandled);
|
|
521
|
+
process.off('uncaughtException', onUnhandled);
|
|
522
|
+
await sendHeartbeat('shutting_down');
|
|
523
|
+
await runner.stop();
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
//# sourceMappingURL=graphile-worker-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphile-worker-runner.js","sourceRoot":"","sources":["../../src/lib/graphile-worker-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphile-worker-runner.test.d.ts","sourceRoot":"","sources":["../../src/lib/graphile-worker-runner.test.ts"],"names":[],"mappings":""}
|