Nobody has started this yet — be first.
Business impact
If the thing meant to protect your service's latency (the rate limiter) becomes the cause of latency -- a struggling Redis instance, say -- that should be visible and alertable well before customers notice. Without a per-decision latency metric, that degradation is invisible until it's already user-facing, turning a preventable, quietly-escalating problem into a customer-facing incident with no early warning. Build-info similarly matters operationally: during an incident, "did the fix actually deploy to this environment" is one of the first questions asked, and today there's no way to answer it from /metrics alone.
Problem
internal/api/metrics.go exposes exactly one metric, ratelimiter_decisions_total{rule,allowed} (a counter), recorded from handleCheck and every demo route via recordDecision. There is no per-decision latency metric and no build-info metric.
Current behavior
There is no way to answer, from Prometheus alone, whether the rate limiter itself is adding meaningful latency to requests, or which build/version is actually running in a given environment.
Expected behavior
A new histogram, ratelimiter_decision_duration_seconds, labeled by rule, records how long each Allow/AllowN call takes (wall clock time spent inside the limiter call itself). A new gauge, ratelimiter_build_info, has a constant value of 1 with build-metadata labels. Both are recorded from every place a rate-limit decision is made: handleCheck and the demo routes via middleware.RateLimit.
Steps to reproduce
curl -s -X POST localhost:8080/api/v1/check -d '{"rule":"free-tier","key":"user-123"}' curl -s localhost:8080/metrics | grep ratelimiter_decision_duration_seconds // got: (nothing -- the series does not exist) // want: at least one observation with a rule label
Why this matters
A rate limiter that becomes the slowest thing in your request path (because its backend is struggling) is a classic "the fix became the problem" failure mode, and it's invisible without per-decision latency metrics. Teams that only alert on request-level latency discover this after the fact, when customers are already affected.
Suggested approach
Use promauto.NewHistogramVec / promauto.NewGaugeVec (or NewGauge with a Set(1) if you don't need the label dimension) -- the same package already imported in this file. Time the limiter call with time.Since/time.Now() around the existing limiter.AllowN(...)/limiter.Allow(...) call sites, not around the whole HTTP handler (which would also count JSON encoding, etc.).
Acceptance criteria
Verification
go test ./test/ -run TestTask08 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b feat/latency-metricsFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/latency-metricsSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:8080localhost:6380http://localhost:8081curl localhost:8080/healthz
curl localhost:8080/api/v1/rules
curl -s -X POST localhost:8080/api/v1/check -d '{"rule":"free-tier","key":"user-123"}' | jq
No Docker? STORE_BACKEND=memory is the default, so go run ./cmd/server alone (no Redis needed) exercises everything except the Redis-backed code paths.
Work the tickets in tasks/ (ordered easy → hard); each names one Go test in test/:
make test-race # go test -race -count=1 ./...
go test ./test/ -run TestTask01 -v # a single ticket
./test/run_all.sh # all 15, pass/fail summary
Level 2
Implement a feature
Extend the system within its own patterns.