Skip to content

Give the p95 alert a bucket edge to fire on, and test both percentiles - #389

Merged
aamoghS merged 1 commit into
devfrom
test/latency-percentiles
Sep 18, 2026
Merged

aamoghS merged 1 commit into
devfrom
test/latency-percentiles

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

The bug

PortalApiSlow alerts on p95 > 2s, but the histogram had no bucket edge at 2 — the edges ran … 1, 1.5, 2.5, 5, 10. A quantile is interpolated inside whichever bucket it lands in, so every p95 that alert has ever fired on was a straight line drawn across the range the threshold sits in.

That is the same flaw 0.75 and 1.5 were added to fix, missed one level up. 5 was already an edge, so PortalApiTailSlow (p99 > 5) was fine.

Fix is one bucket edge at 2. Additive — it adds an le="2" series and changes nothing already recorded.

The tests that found it

Buckets — climb, never repeat; every latency threshold the rules alert on has an exact edge under it (this is the one that failed); nothing above 0.5s more than doubles, since that is where the alerts live.

Percentile math — a local implementation of Prometheus histogram_quantile run against the real edges:

  • a healthy service sits under both thresholds
  • 3% of calls at 4s moves p99 past 2.5 while p95 stays under 2 — the documented reason both are recorded
  • a uniformly slow service trips both
  • a reported quantile never escapes the bucket its true value lands in
  • anything past 10s reads as exactly 10, because +Inf has no upper edge to interpolate towards

The rules — every histogram_quantile reads _bucket grouped by le, which is the difference between a working alert and one that silently never fires; p99 is recorded both overall and per procedure; every recorded name an alert references exists.

Coverage — all 156 procedures the router exposes carry the same timing middleware, asserted by identity against the one on publicProcedure. A procedure without it contributes to no percentile at all, however slow it gets. Paths are also checked to match [a-zA-Z0-9.]+, so the label stays bounded.

What this does not do

Measure real latency. That needs a running instance and a load generator against live Neon. This tests the machinery that reports p95/p99 — that it can express the numbers, that the alerts read it correctly, and that nothing is unmeasured.

14 tests, all passing.

PortalApiSlow alerts on p95 > 2s, but the histogram had no edge at 2 — the
edges ran 1.5 then 2.5. A quantile is interpolated inside whichever bucket it
lands in, so every p95 that alert ever fired on was a straight line drawn
across the range the threshold sits in. That is the same flaw 0.75 and 1.5 were
added to fix, missed one level up. 5 was already an edge, so the p99 alert was
fine.

The tests that found it cover the machinery end to end: the buckets climb and
never repeat, every latency threshold the rules alert on has an exact edge
under it, and nothing above 0.5s more than doubles. A local implementation of
histogram_quantile runs against the real edges — a healthy service sits under
both thresholds, 3% of calls at 4s moves p99 past 2.5 while p95 stays under 2,
a uniformly slow service trips both, a reported quantile never escapes the
bucket its true value lands in, and nothing past 10s can read as more than 10
because +Inf has no upper edge to interpolate towards.

The rules themselves are checked too: every histogram_quantile reads _bucket
grouped by le, which is the difference between an alert and one that silently
never fires, and every recorded name an alert references exists.

Coverage last: all 156 procedures the router exposes carry the same timing
middleware, by identity. One without it contributes to no percentile at all,
however slow it gets.
@github-actions
github-actions Bot requested a review from aamoghS as a code owner September 18, 2026 03:02
@aamoghS aamoghS changed the title Feature: test/latency-percentiles to dev Give the p95 alert a bucket edge to fire on, and test both percentiles Sep 18, 2026
@aamoghS
aamoghS merged commit 26d900f into dev Sep 18, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant