From e14a8ee8f0e4111f46f24410f0c2a117a937499c Mon Sep 17 00:00:00 2001 From: seb Date: Mon, 19 Oct 2026 01:53:25 +0200 Subject: [PATCH] u --- docs/api/routes-all.md | 2 +- docs/api/routes.md | 2 +- docs/api/routes/health/latency.md | 8 +++++++- src/api/routes/health.js | 19 ++++++++++++++++--- src/services/healthMonitorService.js | 7 +++++-- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/docs/api/routes-all.md b/docs/api/routes-all.md index 6a3c18a..7545895 100644 --- a/docs/api/routes-all.md +++ b/docs/api/routes-all.md @@ -499,7 +499,7 @@ _none_ _none_ - Returns: `200 { ok: bool }` #### Health latency history — `GET /health/latency` -_none_ +- Params: `query: range?: str` - Returns: `200 { raw: { timestamp: int, value: num }[], avg: { timestamp: int, value: num }[], max: { timestamp: int, value: num }[] }` ### Section: /image diff --git a/docs/api/routes.md b/docs/api/routes.md index 6da7203..53e8a41 100644 --- a/docs/api/routes.md +++ b/docs/api/routes.md @@ -384,7 +384,7 @@ _none_ ### Section: /health #### Health latency history — `GET /health/latency` -_none_ +- Params: `query: range?: str` - Returns: `200 { raw: { timestamp: int, value: num }[], avg: { timestamp: int, value: num }[], max: { timestamp: int, value: num }[] }` ### Section: /labeltemplate diff --git a/docs/api/routes/health/latency.md b/docs/api/routes/health/latency.md index 23b4d94..7834073 100644 --- a/docs/api/routes/health/latency.md +++ b/docs/api/routes/health/latency.md @@ -4,7 +4,13 @@ Protected. Requires a valid session cookie (`credentials: 'include'`). Health latency history -Returns the database healthcheck latency (ms) as three series, each oldest first with unix-ms timestamps. `raw` holds the per-minute samples of the last 3 hours; `avg` and `max` hold the 30-minute aggregates (over the last 4 hours of samples) kept for 30 days. Requires a valid JWT; no company selection needed. +Returns the database healthcheck latency (ms), each series oldest first with unix-ms timestamps. By default (`range=3h`) only `raw` is returned, the per-minute samples of the last 3 hours. With `range=all` the 30-day `avg` and `max` series (30-minute aggregates over the last 4 hours of samples) are included as well. Requires a valid JWT; no company selection needed. + +## Query parameters + +| Param | Required | Type | Description | +|-------|----------|------|-------------| +| `range` | no | string | `3h` (default) returns only the per-minute samples of the last 3 hours; `all` also includes the 30-day avg and max series. | ## Response `200` diff --git a/src/api/routes/health.js b/src/api/routes/health.js index fc78488..2b373bb 100644 --- a/src/api/routes/health.js +++ b/src/api/routes/health.js @@ -65,7 +65,16 @@ export function register(app, basePath = '') { * get: * tags: [Health] * summary: Health latency history - * description: Returns the database healthcheck latency (ms) as three series, each oldest first with unix-ms timestamps. `raw` holds the per-minute samples of the last 3 hours; `avg` and `max` hold the 30-minute aggregates (over the last 4 hours of samples) kept for 30 days. Requires a valid JWT; no company selection needed. + * description: Returns the database healthcheck latency (ms), each series oldest first with unix-ms timestamps. By default (`range=3h`) only `raw` is returned, the per-minute samples of the last 3 hours. With `range=all` the 30-day `avg` and `max` series (30-minute aggregates over the last 4 hours of samples) are included as well. Requires a valid JWT; no company selection needed. + * parameters: + * - in: query + * name: range + * required: false + * schema: + * type: string + * enum: [3h, all] + * default: 3h + * description: "`3h` (default) returns only the per-minute samples of the last 3 hours; `all` also includes the 30-day avg and max series." * responses: * 200: * description: Latency series @@ -101,9 +110,13 @@ export function register(app, basePath = '') { */ // #region GET /health/latency - app.get(`${basePath}/health/latency`, async (_request, response) => { + app.get(`${basePath}/health/latency`, async (request, response) => { try { - response.json(await getLatencySeries()); + const { range = '3h' } = request.query; + if (range !== '3h' && range !== 'all') { + return response.status(400).json({ error: 'range must be 3h or all' }); + } + response.json(await getLatencySeries({ range })); } catch (error) { console.error('GET /health/latency failed:', error); response.status(500).json({ error: error.message }); diff --git a/src/services/healthMonitorService.js b/src/services/healthMonitorService.js index 398cd28..c91dba8 100644 --- a/src/services/healthMonitorService.js +++ b/src/services/healthMonitorService.js @@ -97,14 +97,17 @@ export function performHealthSelftest() { }); } -// MARK: returns raw (3h), avg and max (30d) latency series as [{ timestamp, value }] oldest first -export async function getLatencySeries() { +// MARK: returns latency series as [{ timestamp, value }] oldest first; range '3h' (default) = raw only, 'all' = raw + avg + max +export async function getLatencySeries({ range = '3h' } = {}) { const redis = getRedisClient(); const parse = (members) => members.map((m) => { const i = m.indexOf(':'); return { timestamp: Number(m.slice(0, i)), value: Number(m.slice(i + 1)) }; }); + if (range === '3h') { + return { raw: parse(await redis.zrange(rawKey(), 0, -1)) }; + } const [raw, avg, max] = await Promise.all([ redis.zrange(rawKey(), 0, -1), redis.zrange(avgKey(), 0, -1),