Nobody has started this yet — be first.
Business impact
Under real concurrent load -- multiple cities fetched in parallel, which is this feature's entire reason to exist -- the dashboard endpoint can return corrupted results: city entries missing, duplicated, or a response whose result count doesn't match the number of saved cities, because multiple goroutines are mutating the same slice concurrently without synchronization. This is the class of bug that passes every manual test (works fine on a laptop, most of the time) and then intermittently corrupts production responses under real traffic -- exactly why this project's own README calls out "confirm no data races on the shared results collection" as a hard requirement, not a nice-to-have.
Problem
FetchAll now builds results by having every goroutine call results = append(results, f.fetchOne(gctx, city)) against one shared, unsynchronized []CityResult variable, instead of each goroutine writing to its own pre-assigned index of a slice sized up front.
Current behavior
go test -race reports a genuine DATA RACE on the shared results slice; without -race, the same unsynchronized append can silently lose an update, producing a dashboard response with fewer results than saved cities.
Expected behavior
Each goroutine writes only to its own index of a slice sized up front (results := make([]CityResult, len(cityNames)); results[i] = ...), which is race-free without needing a mutex because no two goroutines ever touch the same memory location.
Steps to reproduce
go test -race ./internal/dashboard/... -run TestFetchAll_ConcurrentPartialFailure -v
Why this matters
append on a slice shared across goroutines is unsafe even when it "usually looks fine" in casual testing, because append reads the slice header (len/cap/pointer), decides whether to reallocate, and writes back a new header -- none of that is atomic, so two goroutines racing through it can both read the same starting state and each overwrite the other's update, silently dropping a result, independent of whether the race detector happens to be running to catch it.
Suggested approach
Compare the current FetchAll against its own doc comment two lines above the function (still describing the pre-sized, indexed-write approach) and against Benchmark's sequential loop just below in the same file, which never had this problem because it doesn't run concurrently. The fix is a return to indexed writes into a pre-sized slice, keeping the same errgroup/SetLimit concurrency bound unchanged.
Acceptance criteria
Verification
go test -race ./practicetickets/... -run TestTicket10 -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/dashboard-results-raceFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/dashboard-results-raceSubmit 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.