# Preventing goroutine leaks

# The done Channel Pattern

```go
func doWork(done <-chan interface{}) <-chan interface{} {
    terminated := make(chan interface{})
    go func() {
        defer close(terminated)
        for {
            select {
            case s := <-strings:
                // Do work
            case <-done:  // Parent says "stop working"
                return
            }
        }
    }()
    return terminated
}
```

**Key insight**: Pass a `done` channel to every goroutine so the parent can signal cancellation.

# Preventing Goroutine Leaks

## **Without cancellation** (bad):

```go
newRandStream := func() <-chan int {
    randStream := make(chan int)
    go func() {
        for {
            randStream <- rand.Int()  // runs forever!
        }
    }()
    return randStream
}
```

## **With cancellation** (good):

```go
newRandStream := func(done <-chan interface{}) <-chan int {
    randStream := make(chan int)
    go func() {
        defer close(randStream)
        for {
            select {
            case randStream <- rand.Int():
            case <-done:
                return  // clean exit
            }
        }
    }()
    return randStream
}
```

# for-select Loop Pattern

This pattern shows up everywhere in Go:

```go
for {
    select {
    case <-done:
        return
    default:
        // do non-preemptable work
    }
}
```

**Two variations**:

* **With default**: Non-blocking, checks done channel between work
    
* **Without default**: Blocking, waits for channels
