Janitor evicts active keys almost immediately
Nobody has started this yet — be first.
Business impact
Rate-limit tiers are how the product enforces its pricing model and how infrastructure cost stays bounded under abuse. If configured state resets far more often than IDLE_TTL promises, free-tier usage stops being meaningfully capped. Because this bug produces more allowed traffic rather than errors, it is one of the quietest possible failures to notice -- nothing looks broken from the outside, the bill or the abuse just creeps up.
Problem
The janitor is supposed to delete only keys idle for longer than idleTTL. Instead it deletes keys almost immediately after they're created or touched, well before idleTTL has elapsed.
Current behavior
newJanitor's sweep computes a cutoff that ends up in the future relative to "now," not the past -- so every entry's last-access timestamp looks "idle" on the very next sweep tick, no matter how recently it was actually touched.
Expected behavior
Only entries whose last access was more than idleTTL in the past should be deleted. An entry touched within the last idleTTL must survive any number of sweep ticks.
Steps to reproduce
tb := ratelimit.NewTokenBucketMemory(1, 0, 2time.Second / idleTTL */) tb.Allow(ctx, "user-1") // consumes the only token -> Allowed: true res, _ := tb.Allow(ctx, "user-1") // res.Allowed == false, correctly denied time.Sleep(1300 * time.Millisecond) // well under idleTTL=2s, past at least one sweep tick res, _ = tb.Allow(ctx, "user-1") // got: Allowed: true -- the janitor silently evicted the entry and it was recreated fresh // want: Allowed: false -- only ~1.3s of a 2s idleTTL had elapsed; the key was NOT idle
Why this matters
This turns "idle key garbage collection" into "state silently resets on a timer regardless of activity," for every algorithm and both backends that embed a janitor. In production, IDLE_TTL=1h (the documented default) would behave nothing like advertised.
Suggested approach
Look at how cutoff is derived from time.Now() and j.idleTTL in (*janitor).run, and compare it to what "idle for longer than idleTTL" actually requires arithmetically -- a point in the past, idleTTL behind now, not ahead of it.
Acceptance criteria
- A key touched more recently than idleTTL ago survives any number of janitor sweep ticks
- A key genuinely untouched for longer than idleTTL is still evicted (don't just remove the eviction entirely)
- go test ./test/ -run TestTask06 -v passes
Verification
go test ./test/ -run TestTask06 -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
$git checkout -b fix/janitor-cutoff-signFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/janitor-cutoff-signSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
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