Nobody has started this yet — be first.
Business impact
Once any city is fetched successfully a single time, the dashboard serves that exact same reading forever -- the temperature, description, and humidity from that first fetch, no matter how much real time passes or how many times the upstream weather API is called for other cities. Users see a "sunny, 22°C" dashboard during a thunderstorm three days later. Because Status still reports "fresh" (not "stale", which would at least visibly flag the problem), there is no user-visible signal anything is wrong -- this fails completely silently, which is the worst way for a weather app's core feature to break.
Problem
Cache.Get computes freshness as "entry's cachedAt minus the current time", compared against the TTL. Since cachedAt is always in the past (or exactly now) relative to the current time, that subtraction is always zero or negative -- and a non-positive duration is always less than any positive TTL, so Fresh is always true, regardless of how long ago the entry was actually cached.
Current behavior
A cache entry that is well past its TTL still reports Fresh: true; the dashboard keeps serving the same weather reading indefinitely with status "fresh", never falling back to a fresh upstream fetch.
Expected behavior
Freshness should be computed as how much time has elapsed since caching -- the current time minus cachedAt -- compared against the TTL, so an entry correctly reports Fresh: false once that elapsed time exceeds the configured TTL.
Steps to reproduce
cache.Set("Tokyo", weather) // cached at time T // advance time to T + 11 minutes, with a 10-minute TTL entry, found := cache.Get("Tokyo") // Expected: found == true, entry.Fresh == false (present, but past TTL) // Actual: entry.Fresh == true
Why this matters
a.Sub(b) computes a - b, and subtraction is not commutative -- swapping the receiver and the argument silently produces the negated duration, which still type-checks and still compiles (both are time.Duration), so nothing catches this except actually reasoning about (or testing) what the sign of the result means.
Suggested approach
Work out, on paper, what "the cached time minus the current time" represents for a cachedAt that is always in the past relative to "now", versus what "the current time minus the cached time" represents -- then compare against the correct, adjacent use of now() in Cache.Set a few lines above, for which operand plays which role.
Acceptance criteria
Verification
go test ./practicetickets/... -run TestTicket08 -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/cache-never-expiresFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/cache-never-expiresSubmit 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 inweather_dashboarddbappmockweatherWEATHER_API_BASE_URL=https://api.openweathermap.orgWEATHER_API_KEYdocker-compose.prod.ymlRun the project's own test suite:
make test # go test ./...
make test-race # go test -race ./... (includes the concurrency/partial-failure test)
Work the tickets in PRACTICE_TICKETS.md (TICKET-01 through TICKET-10); each names one Go test in practicetickets/:
./practice_tickets_run.sh # all 10, pass/fail summary
go test ./practicetickets/... -run TestTicket01 -v # a single ticket
go test -race ./practicetickets/... -run TestTicket10 -v # ticket 10 needs -race to observe its bug
Tickets 03, 04, 05, and 06 touch the saved-cities Postgres store and need a reachable test database, set via WD_TEST_DATABASE_URL (defaults to postgres://postgres:postgres@localhost:5436/weather_dashboard_test if unset). Tickets 01, 02, 07, 08, 09, and 10 need no database at all.
Level 1
Fix a bug
Read existing behaviour, correct it.