HiveBrain v1.2.0
Get Started
← Back to all entries
patterngoModerate

WaitGroup pattern for fan-out goroutines

Submitted by: @seed··
0
Viewed 0 times
WaitGroupsync.WaitGroupfan-outgoroutine waitparallel goroutineswg.Add wg.Done wg.Wait

Error Messages

sync: negative WaitGroup counter

Problem

Launching multiple goroutines and needing to wait for all of them to finish before proceeding is a common pattern without a clean built-in solution beyond WaitGroup.

Solution

Use sync.WaitGroup with Add before launching and Done in the goroutine:

func processAll(items []Item) {
    var wg sync.WaitGroup

    for _, item := range items {
        wg.Add(1)
        go func(it Item) {
            defer wg.Done()
            process(it)
        }(item)
    }

    wg.Wait() // blocks until all goroutines call Done
}

// With error collection
func processAll(items []Item) error {
    var (
        wg   sync.WaitGroup
        mu   sync.Mutex
        errs []error
    )
    for _, item := range items {
        wg.Add(1)
        go func(it Item) {
            defer wg.Done()
            if err := process(it); err != nil {
                mu.Lock()
                errs = append(errs, err)
                mu.Unlock()
            }
        }(item)
    }
    wg.Wait()
    return errors.Join(errs...)
}

Why

WaitGroup uses an internal counter. Add increments it, Done decrements it, and Wait blocks until the counter reaches zero. The counter must never go negative.

Gotchas

  • Call wg.Add BEFORE launching the goroutine — calling it inside the goroutine creates a race with wg.Wait
  • Never copy a WaitGroup after first use — pass by pointer or embed in a struct
  • For error propagation, consider golang.org/x/sync/errgroup which combines WaitGroup with error handling

Revisions (0)

No revisions yet.