Files
FabledSteward/plugins/traefik/migrations/versions/traefik_007_latency_nullable.py
T
bvandeusenandClaude Opus 5.5 98a0ced5eb
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m23s
CI / unit (push) Successful in 1m27s
CI / publish (push) Successful in 17s
fix(traefik): latency is each scrape's own percentile, every label set summed (#5755)
#5755 "Traefik latency was a percentile of every response since Traefik
started, over unsummed label sets". _percentile_ms read the duration
histogram as it stood, which counts from Traefik's start, so p50/p95/p99 were
lifetime figures that barely moved. It also walked every code/method label
set's buckets as one unsummed list, so equal counts from two sets returned
an edge exactly: nextcloud's flat 100.0 ms p95.

service_buckets() now takes each bucket's rise since the previous scrape,
summed per le over every label set. A scrape with no responses, and the
first scrape, record no latency: traefik_007_latency_nullable lets the
columns be NULL, the batch skips the figure, and the page shows "—".

Found while preparing #5741 "Traefik routers are graded against their own
normal", which grades p95 against a learned normal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:45:07 -04:00

31 lines
993 B
Python

"""A router's latency may be absent
Latency is now each scrape's own percentile (#5741), and a scrape in which a
router answered nothing has none: those rows carry NULL rather than a
made-up 0 or the old lifetime figure.
Revision ID: traefik_007_latency_nullable
Revises: traefik_006_status_codes
Create Date: 2026-10-14
"""
from typing import Sequence, Union
from alembic import op
revision: str = "traefik_007_latency_nullable"
down_revision: Union[str, None] = "traefik_006_status_codes"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
_COLUMNS = ("latency_p50_ms", "latency_p95_ms", "latency_p99_ms")
def upgrade() -> None:
for column in _COLUMNS:
op.alter_column("traefik_metrics", column, nullable=True)
def downgrade() -> None:
for column in _COLUMNS:
op.execute(f"UPDATE traefik_metrics SET {column} = 0 WHERE {column} IS NULL")
op.alter_column("traefik_metrics", column, nullable=False)