Go

Lesson 07

Goroutines and channel ownership

Make goroutine lifetime and channel closing ownership explicit so concurrent code can stop cleanly.

Good Code

reviews/worker.go
func StartWorker(ctx context.Context, jobs <-chan Job, results chan<- Result) {
    go func() {
        defer close(results)

        for {
            select {
            case <-ctx.Done():
                return
            case job, ok := <-jobs:
                if !ok {
                    return
                }
                results <- process(job)
            }
        }
    }()
}

Bad Code

reviews/worker.go
func StartWorker(jobs chan Job, results chan Result) {
    go func() {
        for job := range jobs {
            results <- process(job)
        }
    }()
}

func StopWorker(results chan Result) {
    close(results)
}

Review Notes

What to review

Good Code

The good version shows who reads, who writes, who closes the output channel, and how the goroutine exits when the context is canceled.

Bad Code

The bad version leaves lifetime implicit and lets a separate function close a channel it does not own.

Takeaways

  • The code that starts a goroutine should make its stop condition and channel ownership visible.