Nobody has started this yet — be first.
Business impact
The entire point of this project's retry/backoff logic is to absorb the kind of brief hiccup a real external API has constantly -- and a plain timeout is the single most common kind of hiccup. Right now, a timeout is treated as a permanent, non-retryable failure: one slow response from the upstream weather API and that city instantly shows an error (or falls back to possibly-stale cache) with zero retry attempts, even though the retry mechanism exists and is fully configured to handle exactly this case for every other kind of transient failure.
Problem
IsTransient decides which failures are worth retrying. It currently does not consider ErrUpstreamTimeout transient -- only rate-limiting and generic upstream-unavailable errors are retried. A timeout goes straight to "fail immediately," bypassing the retry loop in Client.FetchCurrent entirely.
Current behavior
A city whose upstream request times out shows an error (or falls back to a stale cache entry) after exactly one attempt, even though WEATHER_MAX_RETRIES is configured to retry transient failures.
Expected behavior
A timeout is treated as transient, exactly like a 5xx or a connection error -- it gets retried (bounded, with backoff) the same as any other transient failure.
Steps to reproduce
Point a Client at a test server that times out on its first request and succeeds on its second, with MaxRetries >= 1. client.FetchCurrent(ctx, "London")
Why this matters
IsTransient is a simple || chain over sentinel errors -- dropping one arm of that chain is a one-line change with no compile-time signal, and it silently reclassifies an entire category of real-world failure from "worth retrying" to "give up immediately," directly undermining the resilience story this whole project is built around.
Suggested approach
Look at the || chain inside IsTransient and compare it against the doc comment directly above ErrUpstreamTimeout in the same file, which still describes it as something worth retrying.
Acceptance criteria
Verification
go test ./practicetickets/... -run TestTicket01 -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/timeout-not-retriedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/timeout-not-retriedSubmit 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.