@rulemetric/cli 0.1.1 → 0.2.1
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 +530 -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/handlers/process-session-goal.d.ts +29 -0
- package/dist/lib/handlers/process-session-goal.d.ts.map +1 -0
- package/dist/lib/handlers/process-session-goal.js +74 -0
- package/dist/lib/handlers/process-session-goal.js.map +1 -0
- package/dist/lib/handlers/process-session-goal.test.d.ts +2 -0
- package/dist/lib/handlers/process-session-goal.test.d.ts.map +1 -0
- package/dist/lib/handlers/process-session-goal.test.js +134 -0
- package/dist/lib/handlers/process-session-goal.test.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 +21 -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,153 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { watchdogVerdict, watchdogStatus, parsePoolerSockets, reclaimStaleLocks, } from './graphile-worker-runner.js';
|
|
3
|
+
const baseState = () => ({
|
|
4
|
+
consecutiveHeartbeatFailures: 0,
|
|
5
|
+
lastListenSuccessAt: null,
|
|
6
|
+
lastListenErrorAt: null,
|
|
7
|
+
});
|
|
8
|
+
describe('watchdogVerdict', () => {
|
|
9
|
+
// The verdict function never returns a reason. Both signals it used to
|
|
10
|
+
// exit on (heartbeat failures, pg LISTEN dead) fire reliably during
|
|
11
|
+
// Supavisor pool pressure even when the worker itself is healthy.
|
|
12
|
+
// Exiting turned transient outages into launchd respawn loops that
|
|
13
|
+
// stacked sockets onto an already-saturated pooler — the EMAXCONN
|
|
14
|
+
// cascade reproduced in scripts/repro-pool-cascade.sh injections C and D.
|
|
15
|
+
// Visibility now goes through watchdogStatus() → heartbeat lastError.
|
|
16
|
+
it('returns null on a healthy boot (no errors yet)', () => {
|
|
17
|
+
expect(watchdogVerdict(baseState(), 1_000_000)).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
it('does NOT fire on heartbeat failures alone — API outage must not kill the worker', () => {
|
|
20
|
+
expect(watchdogVerdict({ ...baseState(), consecutiveHeartbeatFailures: 99 }, 0)).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
it('does NOT fire on prolonged LISTEN-dead — pool pressure must not kill the worker', () => {
|
|
23
|
+
const state = {
|
|
24
|
+
consecutiveHeartbeatFailures: 0,
|
|
25
|
+
lastListenErrorAt: 1_000_000,
|
|
26
|
+
lastListenSuccessAt: null,
|
|
27
|
+
};
|
|
28
|
+
// 10 minutes past last LISTEN error with no recovery — old code exited here.
|
|
29
|
+
expect(watchdogVerdict(state, 1_000_000 + 600_000)).toBeNull();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('watchdogStatus', () => {
|
|
33
|
+
// Replacement for the exit paths: surface the same signals via a string
|
|
34
|
+
// the heartbeat merges into `lastError` so the dashboard can flag wedged
|
|
35
|
+
// workers without launchd respawning them.
|
|
36
|
+
it('returns null when everything is healthy', () => {
|
|
37
|
+
expect(watchdogStatus(baseState(), 1_000_000)).toBeNull();
|
|
38
|
+
});
|
|
39
|
+
it('returns null when recent failures are below the heartbeat limit', () => {
|
|
40
|
+
expect(watchdogStatus({ ...baseState(), consecutiveHeartbeatFailures: 4 }, 0)).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
it('reports persistent heartbeat failures', () => {
|
|
43
|
+
const status = watchdogStatus({ ...baseState(), consecutiveHeartbeatFailures: 5 }, 0);
|
|
44
|
+
expect(status).toMatch(/heartbeat has failed 5/);
|
|
45
|
+
});
|
|
46
|
+
it('reports a stuck LISTEN past the threshold', () => {
|
|
47
|
+
const state = {
|
|
48
|
+
consecutiveHeartbeatFailures: 0,
|
|
49
|
+
lastListenErrorAt: 1_000_000,
|
|
50
|
+
lastListenSuccessAt: null,
|
|
51
|
+
};
|
|
52
|
+
expect(watchdogStatus(state, 1_000_000 + 180_001)).toMatch(/pg listen has been failing/);
|
|
53
|
+
});
|
|
54
|
+
it('does not report LISTEN failures that recovered', () => {
|
|
55
|
+
const state = {
|
|
56
|
+
consecutiveHeartbeatFailures: 0,
|
|
57
|
+
lastListenErrorAt: 1_000_000,
|
|
58
|
+
lastListenSuccessAt: 1_005_000,
|
|
59
|
+
};
|
|
60
|
+
expect(watchdogStatus(state, 1_999_999)).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
it('does not report a fresh LISTEN error below the threshold', () => {
|
|
63
|
+
const state = {
|
|
64
|
+
consecutiveHeartbeatFailures: 0,
|
|
65
|
+
lastListenErrorAt: 1_000_000,
|
|
66
|
+
lastListenSuccessAt: null,
|
|
67
|
+
};
|
|
68
|
+
expect(watchdogStatus(state, 1_000_000 + 60_000)).toBeNull();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('parsePoolerSockets', () => {
|
|
72
|
+
// The worker connects via the SESSION pooler (:5432, see deriveSessionPoolerUrl
|
|
73
|
+
// in commands/evals/listen.ts); the API uses the TRANSACTION pooler (:6543).
|
|
74
|
+
// A counter that matched only :6543 reported 0 sockets for every worker —
|
|
75
|
+
// a monitoring blind spot. parsePoolerSockets must count both pooler ports.
|
|
76
|
+
it('counts session-pooler sockets (:5432), grouped by remote host', () => {
|
|
77
|
+
const lsof = [
|
|
78
|
+
'COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME',
|
|
79
|
+
'node 99860 nick 25u IPv4 0xaa 0t0 TCP 192.168.1.5:51000->18.214.78.123:5432 (ESTABLISHED)',
|
|
80
|
+
'node 99860 nick 26u IPv4 0xab 0t0 TCP 192.168.1.5:51001->3.227.209.82:5432 (ESTABLISHED)',
|
|
81
|
+
'node 99860 nick 27u IPv4 0xac 0t0 TCP 192.168.1.5:51002->18.214.78.123:5432 (ESTABLISHED)',
|
|
82
|
+
].join('\n');
|
|
83
|
+
expect(parsePoolerSockets(lsof)).toEqual({
|
|
84
|
+
total: 3,
|
|
85
|
+
byNode: { '18.214.78.123': 2, '3.227.209.82': 1 },
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it('counts transaction-pooler sockets (:6543) too', () => {
|
|
89
|
+
const lsof = 'node 1 u 1u IPv4 0x 0t0 TCP 10.0.0.1:5000->5.6.7.8:6543 (ESTABLISHED)';
|
|
90
|
+
expect(parsePoolerSockets(lsof)).toEqual({ total: 1, byNode: { '5.6.7.8': 1 } });
|
|
91
|
+
});
|
|
92
|
+
it('matches the REMOTE port only — a local :5432 source port is not counted', () => {
|
|
93
|
+
// Local side is :5432; the remote port is :443. The `->` anchor must
|
|
94
|
+
// prevent this from being counted as a pooler socket.
|
|
95
|
+
const lsof = 'node 1 u 1u IPv4 0x 0t0 TCP 127.0.0.1:5432->1.2.3.4:443 (ESTABLISHED)';
|
|
96
|
+
expect(parsePoolerSockets(lsof)).toEqual({ total: 0, byNode: {} });
|
|
97
|
+
});
|
|
98
|
+
it('returns zero for output with no pooler sockets', () => {
|
|
99
|
+
expect(parsePoolerSockets('')).toEqual({ total: 0, byNode: {} });
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe('reclaimStaleLocks', () => {
|
|
103
|
+
// Workers crash mid-job (SIGKILL, OOM, force-shutdown). Their graphile job
|
|
104
|
+
// rows stay with locked_at IS NOT NULL — graphile-worker's "lock timeout"
|
|
105
|
+
// detector only kicks in after a 4-hour TTL by default. Until then the
|
|
106
|
+
// (now-dead) lock blocks claiming the job. At worker boot, no jobs of OUR
|
|
107
|
+
// user are legitimately in flight, so any lock currently held against
|
|
108
|
+
// task identifiers ending `__<our userId>` is by definition stale and
|
|
109
|
+
// safe to release.
|
|
110
|
+
it('runs an UPDATE filtered by the per-user task suffix', async () => {
|
|
111
|
+
const exec = vi.fn().mockResolvedValue([]);
|
|
112
|
+
await reclaimStaleLocks(exec, 'user-abc', () => { });
|
|
113
|
+
expect(exec).toHaveBeenCalledOnce();
|
|
114
|
+
const [sql, params] = exec.mock.calls[0];
|
|
115
|
+
expect(sql).toContain('graphile_worker._private_jobs');
|
|
116
|
+
expect(sql).toMatch(/locked_at\s*=\s*NULL/i);
|
|
117
|
+
expect(sql).toContain('graphile_worker._private_tasks');
|
|
118
|
+
expect(params).toEqual(['%__user-abc']);
|
|
119
|
+
});
|
|
120
|
+
it('logs the reclaim count and identifiers when locks are released', async () => {
|
|
121
|
+
const exec = vi.fn().mockResolvedValue([
|
|
122
|
+
{ id: 100, identifier: 'process_eval__user-abc' },
|
|
123
|
+
{ id: 101, identifier: 'cron_refresh_skills__user-abc' },
|
|
124
|
+
]);
|
|
125
|
+
const log = vi.fn();
|
|
126
|
+
const released = await reclaimStaleLocks(exec, 'user-abc', log);
|
|
127
|
+
expect(released).toBe(2);
|
|
128
|
+
expect(log).toHaveBeenCalledOnce();
|
|
129
|
+
const msg = log.mock.calls[0][0];
|
|
130
|
+
expect(msg).toMatch(/reclaimed 2 stale lock/i);
|
|
131
|
+
expect(msg).toContain('process_eval__user-abc');
|
|
132
|
+
expect(msg).toContain('cron_refresh_skills__user-abc');
|
|
133
|
+
});
|
|
134
|
+
it('stays silent when nothing was stale', async () => {
|
|
135
|
+
const exec = vi.fn().mockResolvedValue([]);
|
|
136
|
+
const log = vi.fn();
|
|
137
|
+
const released = await reclaimStaleLocks(exec, 'user-abc', log);
|
|
138
|
+
expect(released).toBe(0);
|
|
139
|
+
expect(log).not.toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
it('swallows executor errors so a boot-time DB hiccup never blocks the worker', async () => {
|
|
142
|
+
// Reclaim is best-effort. A failing reclaim must not abort startWorker —
|
|
143
|
+
// graphile-worker's own background lock-timeout will eventually free
|
|
144
|
+
// these jobs (~4h), and the worker is more useful alive than dead.
|
|
145
|
+
const exec = vi.fn().mockRejectedValue(new Error('connection refused'));
|
|
146
|
+
const log = vi.fn();
|
|
147
|
+
await expect(reclaimStaleLocks(exec, 'user-abc', log)).resolves.toBe(0);
|
|
148
|
+
// Should log the error so it's visible in the worker log.
|
|
149
|
+
expect(log).toHaveBeenCalled();
|
|
150
|
+
expect(log.mock.calls[0][0]).toMatch(/reclaim.*failed/i);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
//# sourceMappingURL=graphile-worker-runner.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphile-worker-runner.test.js","sourceRoot":"","sources":["../../src/lib/graphile-worker-runner.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-close-stale-sessions.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-close-stale-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAQ5C,eAAO,MAAM,sBAAsB,EAAE,IAOpC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { apiPost } from '../api-client.js';
|
|
2
|
+
export const cronCloseStaleSessions = async (_payload, helpers) => {
|
|
3
|
+
const result = await apiPost('/api/sessions/close-stale', {
|
|
4
|
+
maxAgeHours: 4,
|
|
5
|
+
});
|
|
6
|
+
helpers.logger.info(`Closed ${result.closed} stale session${result.closed === 1 ? '' : 's'} (>${result.maxAgeHours}h idle)`);
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=cron-close-stale-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-close-stale-sessions.js","sourceRoot":"","sources":["../../../src/lib/handlers/cron-close-stale-sessions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAO3C,MAAM,CAAC,MAAM,sBAAsB,GAAS,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAqB,2BAA2B,EAAE;QAC5E,WAAW,EAAE,CAAC;KACf,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,UAAU,MAAM,CAAC,MAAM,iBAAiB,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,MAAM,CAAC,WAAW,SAAS,CACxG,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-data-integrity-audit.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-data-integrity-audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AA0B5C,eAAO,MAAM,sBAAsB,EAAE,IAapC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { apiPost } from '../api-client.js';
|
|
2
|
+
// The notification recipient. The cron worker has no caller context, so we
|
|
3
|
+
// notify the worker's own user (the API key owner — also the platform's
|
|
4
|
+
// superadmin). Override via env if you ever want a dedicated audit account.
|
|
5
|
+
const RECIPIENT_USER_ID = process.env.RULEMETRIC_AUDIT_NOTIFY_USER_ID ??
|
|
6
|
+
process.env.RULEMETRIC_USER_ID ??
|
|
7
|
+
null;
|
|
8
|
+
export const cronDataIntegrityAudit = async (_payload, helpers) => {
|
|
9
|
+
const audit = await apiPost('/api/superadmin/data-integrity-audit', RECIPIENT_USER_ID ? { notifyUserId: RECIPIENT_USER_ID } : {});
|
|
10
|
+
const summary = audit.findings.length
|
|
11
|
+
? audit.findings.map((f) => `${f.label}: ${f.count}`).join('; ')
|
|
12
|
+
: 'all checks passed';
|
|
13
|
+
helpers.logger.info(`Data integrity audit (${audit.generatedAt}): ${summary}` +
|
|
14
|
+
(audit.notificationWritten ? ' [notification written]' : ''));
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=cron-data-integrity-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-data-integrity-audit.js","sourceRoot":"","sources":["../../../src/lib/handlers/cron-data-integrity-audit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAiB3C,2EAA2E;AAC3E,wEAAwE;AACxE,4EAA4E;AAC5E,MAAM,iBAAiB,GACrB,OAAO,CAAC,GAAG,CAAC,+BAA+B;IAC3C,OAAO,CAAC,GAAG,CAAC,kBAAkB;IAC9B,IAAI,CAAC;AAEP,MAAM,CAAC,MAAM,sBAAsB,GAAS,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IACtE,MAAM,KAAK,GAAG,MAAM,OAAO,CACzB,sCAAsC,EACtC,iBAAiB,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAC7D,CAAC;IAEF,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM;QACnC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAChE,CAAC,CAAC,mBAAmB,CAAC;IACxB,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,yBAAyB,KAAK,CAAC,WAAW,MAAM,OAAO,EAAE;QACvD,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,EAAE,CAAC,CAC/D,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-refresh-skills.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-refresh-skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAa5C,eAAO,MAAM,iBAAiB,EAAE,IAsG/B,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { fetchAllSources, TIER_1_SOURCES, TIER_2_SOURCES, loadDiscoveredSources, } from '@rulemetric/skills-registry';
|
|
2
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
const BATCH_SIZE = 200;
|
|
6
|
+
export const cronRefreshSkills = async (_payload, helpers) => {
|
|
7
|
+
// Fail fast when there's no GITHUB_TOKEN. The unauthenticated GitHub API
|
|
8
|
+
// gives 60 req/hr; this cron does 2 calls per source × ~351 sources = 702
|
|
9
|
+
// calls. Without a token we'd exhaust the cap on the first batch, hit
|
|
10
|
+
// Octokit's throttle plugin, and (pre-fix) sleep up to 57 min per source
|
|
11
|
+
// waiting for the rate window to reset — all while holding a graphile
|
|
12
|
+
// concurrency slot. The bounded-retry change in github-fetcher.ts makes
|
|
13
|
+
// that survivable, but we'd still rather skip cleanly than crawl 702 calls
|
|
14
|
+
// just to skip them all individually. Set GITHUB_TOKEN in the worker env
|
|
15
|
+
// (e.g. via launchctl setenv) to enable.
|
|
16
|
+
if (!process.env.GITHUB_TOKEN) {
|
|
17
|
+
helpers.logger.warn('GITHUB_TOKEN unset — skipping skills registry refresh. Without a token the unauthenticated 60 req/hr cap is too tight for ~351 sources; set GITHUB_TOKEN (5000 req/hr) and re-run.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Combine all source tiers + the discovered set so the cron's coverage
|
|
21
|
+
// matches the bundled registry. De-dupe by repo to avoid double-fetching
|
|
22
|
+
// when discovered overlaps with explicit sources.
|
|
23
|
+
const discovered = loadDiscoveredSources();
|
|
24
|
+
const seen = new Set();
|
|
25
|
+
const sources = [...TIER_1_SOURCES, ...TIER_2_SOURCES, ...discovered].filter((s) => {
|
|
26
|
+
if (seen.has(s.repo))
|
|
27
|
+
return false;
|
|
28
|
+
seen.add(s.repo);
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
helpers.logger.info(`Fetching from ${sources.length} sources (T1=${TIER_1_SOURCES.length}, T2=${TIER_2_SOURCES.length}, discovered=${discovered.length})`);
|
|
32
|
+
const result = await fetchAllSources(sources, {
|
|
33
|
+
onProgress: (source, count) => helpers.logger.info(`fetched ${count} from ${source}`),
|
|
34
|
+
});
|
|
35
|
+
// Persist JSON-on-disk view (legacy / fast-path consumers).
|
|
36
|
+
const configDir = path.join(os.homedir(), '.config', 'rulemetric');
|
|
37
|
+
await mkdir(configDir, { recursive: true });
|
|
38
|
+
const outPath = path.join(configDir, 'skills-registry.json');
|
|
39
|
+
await writeFile(outPath, JSON.stringify({ generatedAt: new Date().toISOString(), skills: result.entries }, null, 2));
|
|
40
|
+
helpers.logger.info(`Refreshed disk registry: ${result.entries.length} skills`);
|
|
41
|
+
// Mirror to DB as scope='public' instructions rows so the catalog,
|
|
42
|
+
// recommendations, and suggestion-cron all see one source of truth.
|
|
43
|
+
const apiUrl = process.env.RULEMETRIC_API_URL;
|
|
44
|
+
const botToken = process.env.RULEMETRIC_REGISTRY_BOT_TOKEN;
|
|
45
|
+
if (!apiUrl || !botToken) {
|
|
46
|
+
helpers.logger.warn('RULEMETRIC_API_URL or RULEMETRIC_REGISTRY_BOT_TOKEN unset; skipping DB sync');
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let totalInserted = 0;
|
|
50
|
+
let totalUpdated = 0;
|
|
51
|
+
let totalUnchanged = 0;
|
|
52
|
+
let totalFailed = 0;
|
|
53
|
+
for (let i = 0; i < result.entries.length; i += BATCH_SIZE) {
|
|
54
|
+
const batch = result.entries.slice(i, i + BATCH_SIZE).map((s) => ({
|
|
55
|
+
id: s.id,
|
|
56
|
+
name: s.name,
|
|
57
|
+
description: s.description,
|
|
58
|
+
content: s.content,
|
|
59
|
+
source: s.source,
|
|
60
|
+
tags: s.tags,
|
|
61
|
+
category: s.category,
|
|
62
|
+
updatedAt: s.updatedAt,
|
|
63
|
+
popularity: s.popularity,
|
|
64
|
+
}));
|
|
65
|
+
try {
|
|
66
|
+
const res = await fetch(`${apiUrl}/api/skills/sync-public`, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'content-type': 'application/json',
|
|
70
|
+
authorization: `Bearer ${botToken}`,
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({ skills: batch }),
|
|
73
|
+
});
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
helpers.logger.warn(`Batch ${i / BATCH_SIZE} failed: ${res.status} ${await res.text()}`);
|
|
76
|
+
totalFailed += batch.length;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const json = (await res.json());
|
|
80
|
+
totalInserted += json.inserted;
|
|
81
|
+
totalUpdated += json.updated;
|
|
82
|
+
totalUnchanged += json.unchanged;
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
helpers.logger.warn(`Batch ${i / BATCH_SIZE} threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
86
|
+
totalFailed += batch.length;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
helpers.logger.info(`DB sync: inserted=${totalInserted} updated=${totalUpdated} unchanged=${totalUnchanged} failed=${totalFailed}`);
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=cron-refresh-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-refresh-skills.js","sourceRoot":"","sources":["../../../src/lib/handlers/cron-refresh-skills.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,cAAc,EACd,cAAc,EACd,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,CAAC,MAAM,iBAAiB,GAAS,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IACjE,yEAAyE;IACzE,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,sEAAsE;IACtE,wEAAwE;IACxE,2EAA2E;IAC3E,yEAAyE;IACzE,yCAAyC;IACzC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,oLAAoL,CACrL,CAAC;QACF,OAAO;IACT,CAAC;IAED,uEAAuE;IACvE,yEAAyE;IACzE,kDAAkD;IAClD,MAAM,UAAU,GAAG,qBAAqB,EAAE,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,cAAc,EAAE,GAAG,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACjF,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,OAAO,CAAC,MAAM,gBAAgB,cAAc,CAAC,MAAM,QAAQ,cAAc,CAAC,MAAM,gBAAgB,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAE3J,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE;QAC5C,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,MAAM,EAAE,CAAC;KACtF,CAAC,CAAC;IAEH,4DAA4D;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;IACnE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAC7D,MAAM,SAAS,CACb,OAAO,EACP,IAAI,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAC3F,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC;IAEhF,mEAAmE;IACnE,oEAAoE;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;IAC3D,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,6EAA6E,CAC9E,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,WAAW,GAAG,CAAC,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChE,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU;SACzB,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,yBAAyB,EAAE;gBAC1D,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,QAAQ,EAAE;iBACpC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;aACxC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,UAAU,YAAY,GAAG,CAAC,MAAM,IAAI,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACzF,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;gBAC5B,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAI7B,CAAC;YACF,aAAa,IAAI,IAAI,CAAC,QAAQ,CAAC;YAC/B,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC;YAC7B,cAAc,IAAI,IAAI,CAAC,SAAS,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,UAAU,WAAW,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1G,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,qBAAqB,aAAa,YAAY,YAAY,cAAc,cAAc,WAAW,WAAW,EAAE,CAC/G,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-refresh-skills.test.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-refresh-skills.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Tests for the cron_refresh_skills hang fix.
|
|
2
|
+
//
|
|
3
|
+
// Bug history (2026-05-21 debugging session, follow-up to
|
|
4
|
+
// docs/incidents/2026-05-20-launches-stuck-and-worker-wedge.md task #26):
|
|
5
|
+
//
|
|
6
|
+
// Without a GITHUB_TOKEN the unauthenticated GitHub API caps at 60 req/hr.
|
|
7
|
+
// Pre-fix, `cron_refresh_skills` walked ~351 sources with two API calls each
|
|
8
|
+
// (`repos.get` + `repos.getBranch`) and let Octokit's `throttling` plugin
|
|
9
|
+
// schedule retries via `setTimeout(retryAfter * 1000)`. Observed `retryAfter`
|
|
10
|
+
// values: 1129s → 3450s (~19 → ~57 minutes). The handler slept inside that
|
|
11
|
+
// timer, holding a graphile-worker concurrency slot for up to ~3 hours per
|
|
12
|
+
// run while emitting zero progress logs.
|
|
13
|
+
//
|
|
14
|
+
// Fix has two parts, both tested here:
|
|
15
|
+
//
|
|
16
|
+
// 1. Bounded retry — the throttle callbacks now refuse to retry when
|
|
17
|
+
// `retryAfter` exceeds the budget (5 minutes). The exhausted request
|
|
18
|
+
// throws back into fetchSource's catch, which logs and treats the
|
|
19
|
+
// source as skipped instead of hanging.
|
|
20
|
+
//
|
|
21
|
+
// 2. Fail-fast on missing token — the handler refuses to even attempt the
|
|
22
|
+
// crawl without a `GITHUB_TOKEN`. The 60-req/hr unauthenticated cap is
|
|
23
|
+
// not enough for 351 sources × 2 calls, so attempting is worse than
|
|
24
|
+
// giving up cleanly.
|
|
25
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
26
|
+
import { shouldRetryRateLimit, shouldRetrySecondaryRateLimit, } from '@rulemetric/skills-registry';
|
|
27
|
+
import { cronRefreshSkills } from './cron-refresh-skills.js';
|
|
28
|
+
describe('shouldRetryRateLimit', () => {
|
|
29
|
+
it('returns false when GitHub reports a reset >5 min away', () => {
|
|
30
|
+
// The original symptom: retryAfter=1129 (19 min). Octokit waits the full
|
|
31
|
+
// window before invoking the retry, so returning true here means a worker
|
|
32
|
+
// sleeps ~19 min holding a concurrency slot. Refuse.
|
|
33
|
+
expect(shouldRetryRateLimit(1129, 0)).toBe(false);
|
|
34
|
+
expect(shouldRetryRateLimit(3450, 0)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it('returns true within budget when reset is <5 min and retries left', () => {
|
|
37
|
+
// Short waits (~minutes) are still legitimate — e.g. transient secondary
|
|
38
|
+
// rate. Honour them up to retry budget.
|
|
39
|
+
expect(shouldRetryRateLimit(60, 0)).toBe(true);
|
|
40
|
+
expect(shouldRetryRateLimit(60, 1)).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
it('returns false once the retry budget is exhausted', () => {
|
|
43
|
+
// Default Octokit retryCount semantics: 0 = first retry attempt.
|
|
44
|
+
// We allow up to 2 retries; a 3rd call (retryCount=2) gives up.
|
|
45
|
+
expect(shouldRetryRateLimit(60, 2)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it('treats the 5-minute boundary inclusively (300s is OK, 301s is not)', () => {
|
|
48
|
+
expect(shouldRetryRateLimit(300, 0)).toBe(true);
|
|
49
|
+
expect(shouldRetryRateLimit(301, 0)).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('shouldRetrySecondaryRateLimit', () => {
|
|
53
|
+
// Secondary rate limits = GitHub abuse detection (concurrent same-IP
|
|
54
|
+
// hammering). Pre-fix this always returned true → retry forever, which
|
|
55
|
+
// amplified the primary-limit hang. Same 5-min cap.
|
|
56
|
+
it('returns false when reset is >5 min away', () => {
|
|
57
|
+
expect(shouldRetrySecondaryRateLimit(600)).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
it('returns true for short waits', () => {
|
|
60
|
+
expect(shouldRetrySecondaryRateLimit(30)).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('cronRefreshSkills (GITHUB_TOKEN fail-fast)', () => {
|
|
64
|
+
const origToken = process.env.GITHUB_TOKEN;
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
delete process.env.GITHUB_TOKEN;
|
|
67
|
+
});
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
if (origToken !== undefined) {
|
|
70
|
+
process.env.GITHUB_TOKEN = origToken;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
delete process.env.GITHUB_TOKEN;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
it('skips the crawl when GITHUB_TOKEN is missing and emits an actionable warning', async () => {
|
|
77
|
+
const logs = [];
|
|
78
|
+
const log = (level) => (msg) => {
|
|
79
|
+
logs.push({ level, msg });
|
|
80
|
+
};
|
|
81
|
+
const helpers = {
|
|
82
|
+
job: { id: '1', attempts: 1, max_attempts: 25 },
|
|
83
|
+
logger: { info: log('info'), warn: log('warn'), error: log('error') },
|
|
84
|
+
addJob: vi.fn(),
|
|
85
|
+
};
|
|
86
|
+
const start = Date.now();
|
|
87
|
+
await cronRefreshSkills({}, helpers);
|
|
88
|
+
const duration = Date.now() - start;
|
|
89
|
+
// The skip path should be near-instantaneous (no network) — well under
|
|
90
|
+
// the 60s ish bound the pre-fix path would burn before hitting the cap.
|
|
91
|
+
expect(duration).toBeLessThan(2_000);
|
|
92
|
+
// Must mention GITHUB_TOKEN by name so the operator knows the fix.
|
|
93
|
+
const tokenWarning = logs.find((l) => /GITHUB_TOKEN/i.test(l.msg));
|
|
94
|
+
expect(tokenWarning).toBeDefined();
|
|
95
|
+
expect(tokenWarning.level).toBe('warn');
|
|
96
|
+
});
|
|
97
|
+
it('does not log "Fetching from N sources" when GITHUB_TOKEN is missing', async () => {
|
|
98
|
+
// Pre-fix the handler logged "Fetching from 351 sources" BEFORE realising
|
|
99
|
+
// the futility. The skip-fast path must short-circuit before that.
|
|
100
|
+
const logs = [];
|
|
101
|
+
const helpers = {
|
|
102
|
+
job: { id: '1', attempts: 1, max_attempts: 25 },
|
|
103
|
+
logger: {
|
|
104
|
+
info: (msg) => logs.push(msg),
|
|
105
|
+
warn: (msg) => logs.push(msg),
|
|
106
|
+
error: (msg) => logs.push(msg),
|
|
107
|
+
},
|
|
108
|
+
addJob: vi.fn(),
|
|
109
|
+
};
|
|
110
|
+
await cronRefreshSkills({}, helpers);
|
|
111
|
+
expect(logs.find((m) => /^Fetching from/.test(m))).toBeUndefined();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=cron-refresh-skills.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-refresh-skills.test.js","sourceRoot":"","sources":["../../../src/lib/handlers/cron-refresh-skills.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-regenerate-insights.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-regenerate-insights.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAG5C,eAAO,MAAM,sBAAsB,EAAE,IAGpC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { apiPost } from '../api-client.js';
|
|
2
|
+
export const cronRegenerateInsights = async (_payload, helpers) => {
|
|
3
|
+
await apiPost('/api/insights-jobs/regenerate-all', {});
|
|
4
|
+
helpers.logger.info('Regenerate-stale-insights cron fired');
|
|
5
|
+
};
|
|
6
|
+
//# sourceMappingURL=cron-regenerate-insights.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-regenerate-insights.js","sourceRoot":"","sources":["../../../src/lib/handlers/cron-regenerate-insights.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,MAAM,CAAC,MAAM,sBAAsB,GAAS,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;IACtE,MAAM,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;AAC9D,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-suggest-instructions.d.ts","sourceRoot":"","sources":["../../../src/lib/handlers/cron-suggest-instructions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAmD5C,eAAO,MAAM,uBAAuB,EAAE,IA2IrC,CAAC"}
|