{10x}debuggable
Rate Limiter Service
enhancementintermediateP2pkg/ratelimit/, internal/api/Level 2 · Implement a feature30 XP2–3 hours

Add an admin endpoint to reset a key's limiter state

Nobody has started this yet — be first.

Business impact

"A customer got wrongly throttled" is a routine support request -- shared office IPs, a retry storm, a bug on the customer's side that looked like abuse from ours. Today the only remediation is "wait it out" or "restart the service" (which resets every customer's state, not just theirs). An operator-facing reset endpoint turns a multi-team escalation into a 30-second fix.

Problem

A Resetter interface (Reset(ctx, key) error) already exists as scaffolding in pkg/ratelimit/limiter.go, but nothing implements it yet, and there is no admin route to call it.

Current behavior

Once a key is rate-limited, there is no way to clear its state short of waiting out the window/refill, restarting the process (memory backend), or manually deleting the exact Redis key by hand (Redis backend).

Expected behavior

All six limiter types implement Resetter, restoring a key to a fresh/fully-available state. A new POST /api/v1/reset endpoint (body {"rule","key"}) looks up the rule like /api/v1/check does, type-asserts to Resetter, and returns 204 on success, 404 for an unknown rule, or 501 if the limiter doesn't support Resetter. After a successful reset, the key behaves exactly as if never used.

Steps to reproduce

  1. Exhaust a rule's limit for a key via repeated POST /api/v1/check calls until a 429 is returned.
  2. POST /api/v1/reset with the same rule/key.
  3. Observe: 404, because the route does not exist yet -- there is no way to clear the key's state.

Why this matters

Every production rate limiter needs an operator escape hatch. Without one, "a customer got wrongly throttled" turns into "wait or restart the service," neither of which is acceptable for anything but a toy.

Suggested approach

Memory implementations: state lives in a sync.Map keyed by the same string Allow/AllowN use -- Reset just deletes that entry so the next access recreates a fresh one via the existing LoadOrStore path. Redis implementations: Reset is a DEL on prefix+key, mirroring how the Lua scripts build their key -- check whether the redis.Scripter field type needs widening to expose Del without breaking existing constructors. Wire the route in router.go next to POST /api/v1/check, handler next to handleCheck.

Acceptance criteria

  • All six limiter types implement ratelimit.Resetter
  • POST /api/v1/reset with a valid rule/key returns 204 and the key's state is actually cleared (verified behaviorally, not just "no error")
  • Unknown rule -> 404
  • go test ./test/ -run TestTask05 -v passes

Verification

go test ./test/ -run TestTask05 -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.

01

Branch off your fork

$git checkout -b feat/reset-endpoint
02

Fix it and commit

Meet every acceptance criterion, and add a test that would have caught this.

03

Push the branch

$git push -u origin feat/reset-endpoint
04

Submit it below

Paste your fork URL and the branch name, with a short write-up of the root cause.

Submit your fix

Sign in to submit a solution and track your progress.

Sign in to submit

Questions

Stuck on something?

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 in
No questions yet. If something in this ticket reads ambiguously, you are probably not the only one — ask.