You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
authored
fix(overview): count entities over the period window instead of at an instant (#8)
* fix(overview): count entities active over the month, not at an instant
The snapshot queries ran as instant PromQL at a single timestamp, so they only
counted series that were non-stale at that moment (~5m staleness) — roughly a
third of the active fleet. Wrap each selector in max_over_time(<selector>[window])
where window spans the month up to queryAt, so a snapshot counts every cluster,
node, tenant and app that reported at least once during the month.
This matches the Grafana telemetry-overview dashboard, whose stat panels run
range queries over the selected period rather than a single instant, and fixes
the ~3x undercount on cozystack.io/oss-health/telemetry/.
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
* fix(overview): query quarter/year over their own windows, not by averaging
The month period is still served from the cached monthly snapshot, but quarter
and year are now queried live over 3- and 12-calendar-month windows instead of
averaging per-month snapshots. A cumulative count of distinct clusters over a
multi-month window cannot be recovered from per-month aggregates: a cluster
active in two months must be counted once, and averaging understates the period
total. The longer periods reuse the month's app breakdown to avoid a one-off
load-test burst inflating their max_over_time peak.
Removes the now-unused aggregateSnapshots/filterSnapshotsByMonths helpers and
documents the new behavior in the README.
Signed-off-by: tym83 <6355522@gmail.com>
* perf(overview): cache windowed quarter/year period stats
The quarter and year periods ran windowed max_over_time queries (the year
is a 365d scan over the whole fleet) on every /api/overview request, which
amplifies a cheap public GET into heavy VictoriaMetrics load. Memoize the
computed quarter/year stats per requested month: past months are final and
cached indefinitely, the in-progress month for a short TTL. Concurrent
callers are coalesced via singleflight, mirroring the snapshot path.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
---------
Signed-off-by: Timur Tukaev <timur.tukaev@aenix.io>
Signed-off-by: tym83 <6355522@gmail.com>
Signed-off-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Co-authored-by: Andrei Kvapil <andrei.kvapil@aenix.io>
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,10 +15,10 @@ The server exposes a `GET /api/overview?year=YYYY&month=MM` endpoint that return
15
15
### How it works
16
16
17
17
1. The endpoint requires `year` and `month` query parameters (e.g. `/api/overview?year=2026&month=03`). Requests without them return 400.
18
-
2. On first request for a given month, the server queries VictoriaMetrics at the end of that month, writes a snapshot to `--snapshot-dir`, and caches it in memory. Subsequent requests for the same month are served from cache.
18
+
2. On first request for a given month, the server queries VictoriaMetrics over a window spanning that month, writes a snapshot to `--snapshot-dir`, and caches it in memory. Subsequent requests for the same month are served from cache. Counts use `max_over_time(<selector>[window])` rather than an instant query, so a snapshot reflects every cluster/node/tenant/app that reported at least once during the month — an instant query only sees series that are non-stale at a single timestamp (~5m) and undercounts the active fleet ~3x.
19
19
3. Concurrent requests for the same uncached month are coalesced into a single VictoriaMetrics query (per-month singleflight).
20
20
4. The app list is fetched from [cozystack/cozystack packages/apps](https://github.com/cozystack/cozystack/tree/main/packages/apps) so newly added applications are picked up automatically; a built-in fallback list is used if GitHub is unreachable.
21
-
5. The response aggregates snapshots into three time periods relative to the requested month: **that month**, **last quarter** (3 months), and **last 12 months**.
21
+
5. The response reports three time periods relative to the requested month: **that month**, **last quarter** (3 calendar months) and **last 12 months**. The quarter and year are queried live over their own windows — a cumulative count of distinct clusters over several months cannot be derived by averaging per-month snapshots (a cluster active in two months must be counted once). Their app breakdown reuses the month's, to avoid one-off load-test spikes inflating the longer-window peak. The quarter/year results are memoized per requested month (past months indefinitely, the current month for a short TTL) and concurrent callers are coalesced via singleflight, so repeated requests do not re-run the heavy windowed queries.
22
22
23
23
The snapshot directory is backed by an `emptyDir` volume — cache is per-pod and is rebuilt on restart from VictoriaMetrics on demand.
24
24
@@ -43,8 +43,8 @@ The snapshot directory is backed by an `emptyDir` volume — cache is per-pod an
43
43
"kubernetes": 30
44
44
}
45
45
},
46
-
"quarter": { "..." : "averaged over 3 months" },
47
-
"year": { "..." : "averaged over 12 months" }
46
+
"quarter": { "..." : "distinct over the last 3 calendar months" },
47
+
"year": { "..." : "distinct over the last 12 calendar months" }
0 commit comments