Skip to content

Commit 60db34d

Browse files
admin: cheap ungated /healthz; dashboard probes it (no probe storm) + live screenshot
Downstream polish. The dashboard auto-discovers admin and, by default, probed it at its /admin prefix — but admin's page awaits a full snapshot (probing every sibling) on render, so the probe blew the 3s timeout and admin read as 'down' (and two ops consoles probing each other could storm). Add admin GET <prefix>/healthz: a cheap, ungated liveness endpoint (200 { status, uptime_seconds }, no snapshot, no auth — conventional, like metrics/). serve.js + compose.test.js refine the dashboard's admin probe to /admin/healthz. Now the live demo shows every one of 32 auto-discovered plugins alive (screenshot added to dashboard/README). admin/test.js: healthz is 200 and ungated even when the page is gated.
1 parent ac5e880 commit 60db34d

6 files changed

Lines changed: 34 additions & 0 deletions

File tree

admin/plugin.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,16 @@ ${NOT_POSSIBLE.map(([what, why]) => ` <li><strong>${esc(what)}</strong> —
565565
return snapshot();
566566
});
567567

568+
// Cheap, ungated liveness — no snapshot, no auth (conventional for a
569+
// healthz, like metrics/). It lets another prober (e.g. dashboard/) confirm
570+
// the admin plugin is alive WITHOUT triggering a full page-snapshot render,
571+
// which probes every sibling and would otherwise blow the prober's timeout
572+
// and read as 'down' — and, when two ops consoles probe each other, storm.
573+
api.fastify.get(`${prefix}/healthz`, async (request, reply) => {
574+
reply.header('cache-control', 'no-store');
575+
return { status: 'ok', uptime_seconds: Math.round(process.uptime()) };
576+
});
577+
568578
if (!adminAgents) {
569579
api.log.warn(
570580
`admin: the admin surface at ${prefix}/ is OPEN — no config.adminAgents set, `

admin/test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,17 @@ describe('admin plugin', () => {
181181
}
182182
});
183183

184+
it('healthz is 200 and ungated — liveness needs no auth, even when the page is gated', async () => {
185+
// The page and status.json are gated (above), but healthz must answer
186+
// anonymously so another prober (dashboard/) can check liveness cheaply
187+
// without triggering a full snapshot render.
188+
const res = await get(`${base}/admin/healthz`);
189+
assert.strictEqual(res.status, 200, `healthz: ${res.status}`);
190+
const body = await res.json();
191+
assert.strictEqual(body.status, 'ok');
192+
assert.strictEqual(typeof body.uptime_seconds, 'number');
193+
});
194+
184195
// ------------------------------------------------------------- the page
185196

186197
it('admin GET page → 200 self-contained HTML with plugin ids, pods count, sections', async () => {

compose.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ describe('composition: every plugin on one server', () => {
136136
probes: {
137137
relay: { kind: 'ws' }, webrtc: { kind: 'ws' }, terminal: { kind: 'ws' },
138138
tunnel: { kind: 'ws' }, notifications: { kind: 'ws' },
139+
// admin probes every plugin on page render; hit its cheap
140+
// healthz so the two ops consoles don't storm each other.
141+
admin: { probe: '/admin/healthz', expect: [200] },
139142
},
140143
},
141144
},

dashboard/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ optionally refines a single plugin's probe as `{ probe?, expect?, kind? }`:
7575
- If the dashboard is the only plugin loaded, the page renders with a note
7676
explaining there are no siblings to show.
7777

78+
![The dashboard auto-discovering and probing 32 plugins live on one server](./screenshot.png)
79+
80+
*Live `/dashboard/` from `npm run serve` — 32 plugins auto-discovered via
81+
`api.plugins`, each probed over loopback. `up` = 2xx/3xx or a matched
82+
`expect`; `degraded` = a 4xx from a guarded surface (alive, but a bare-prefix
83+
probe can't say more — finding 1's residual); nothing `down`.*
84+
7885
### The page, in words
7986

8087
A single narrow column, system font, honest table: **plugin | probe |

dashboard/screenshot.png

142 KB
Loading

serve.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ const fastify = createServer({
157157
relay: { kind: 'ws' }, webrtc: { kind: 'ws' }, terminal: { kind: 'ws' },
158158
tunnel: { kind: 'ws' }, notifications: { kind: 'ws' },
159159
pay: { probe: '/paid/demo', expect: [402] },
160+
// admin's page probes every plugin on render; hit its cheap healthz
161+
// instead so the probe is fast and the two consoles don't storm.
162+
admin: { probe: '/admin/healthz', expect: [200] },
160163
},
161164
},
162165
},

0 commit comments

Comments
 (0)