← ClaudeAtlas

go-concurrencylisted

Enforces safe Go concurrency — every goroutine has a known stop condition, context propagates cancellation, channel ownership and direction are explicit, and shared state is protected or not shared. Use when writing or reviewing Go that starts goroutines, uses channels, sync primitives, or context, and when the user mentions goroutine leaks, deadlock, data race, WaitGroup, errgroup, select, mutex, worker pool, "-race", or asks "is this concurrent code safe", "why does this hang".
CasLubbers/code-design-skills · ★ 1 · Code & Development · score 62
Install: claude install-skill CasLubbers/code-design-skills
# Go concurrency Concurrency in Go is cheap to start and expensive to get wrong. The failures — leaks, races, deadlocks — are invisible in the happy path and appear under load. ## Never start a goroutine without knowing how it stops Before writing `go f()`, answer: what makes this return, and who waits for it? A goroutine blocked forever on a channel send or receive is a permanent leak of its stack and everything it references. ```go // Bad — if nobody ever receives, this goroutine never exits go func() { ch <- compute() }() // Good — cancellation ends it, and the caller waits var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() select { case ch <- compute(): case <-ctx.Done(): } }() wg.Wait() ``` The `Add` goes before the `go`, never inside the goroutine — otherwise `Wait` can run first and return immediately. ## Context carries cancellation, not data Pass `ctx` as the first parameter. Never store it in a struct. Every blocking operation selects on `ctx.Done()`, and every function that takes a `ctx` must honour it. ```go func poll(ctx context.Context, interval time.Duration) error { t := time.NewTicker(interval) defer t.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-t.C: if err := checkOnce(ctx); err != nil { return err } } } } ``` Always call the `cancel` returned by `WithCancel` / `WithTimeout`, usually via `defer` — skipping it leaks the timer and