Frontend load test in CI, health page checks Seafile, OnlyOffice, audiobooks, podcasts and Mealie; roadmap updated

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-27 10:33:20 -04:00
1 parent 94d13b82d7
commit db58bfa982
7 files changed
+56 -13

No files matched your search

+5
View File
@@ -679,6 +679,11 @@ async function handleRequest(req, res) {
const ps = plexLoad();
out.plex = !ps.srv ? { configured: false } : await (async () => { const t = Date.now(); try { const r = await fetch(ps.srv + '/identity', { headers: { 'X-Plex-Token': ps.stk || ps.token || '', Accept: 'application/json' }, signal: AbortSignal.timeout(6000) }); return { configured: true, ok: r.ok, ms: Date.now() - t, user: ps.user ? ps.user.title : '' }; } catch (e) { return { configured: true, ok: false, error: e.name === 'TimeoutError' ? 'No answer in 6 seconds' : e.message }; } })();
try { out.mail = await mail.health(); } catch { out.mail = []; }
// the other services the hub leans on: reachable at all? (any answer under 500 counts, since most want a sign-in)
const probe = async (name, url) => { const t = Date.now(); try { const r = await fetch(url, { redirect: 'manual', signal: AbortSignal.timeout(4000) }); return r.status < 500 ? { name, ok: true, ms: Date.now() - t } : { name, ok: false, error: 'Answered with an error (' + r.status + ')' }; } catch (e) { return { name, ok: false, error: e.name === 'TimeoutError' ? 'No answer within 4 seconds' : 'Cannot be reached' }; } };
const checks = [probe('Seafile (Files)', SEAFILE_URL + '/api2/ping/'), probe('OnlyOffice', ONLYOFFICE_URL + '/healthcheck'), probe('Audiobooks', (process.env.OPENAUDIBLE_URL || AUDIOBOOKS_URL).replace(/\/$/, '') + '/'), probe('Podcasts (Podgrab)', PODCAST_URL)];
if (recipes.enabled()) checks.push(probe('Recipes (Mealie)', (process.env.MEALIE_URL || 'https://mealie.necloud.us').replace(/\/+$/, '') + '/api/app/about'));
out.services = await Promise.all(checks);
out.lyrics = lyrics.enabled(); out.signal = signal.enabled(); out.transcripts = transcripts.status();
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' }); return res.end(JSON.stringify(out));
}