💻 Tech
The code below shows a goroutine leak because once the context expires (ctx.Done()), ch <- true becomes a blocking code. If this is a long-running application, like a web server application, the blocking code stays on indefinitely because there will be nothing that will receive the true value. Go garbage collector won’t be able to redeem the resources used by the goroutine because it’s being used even though it doesn’t have any purpose anymore.
To resolve this, we can make the channel a buffered channel by ensuring that there’s always a space to receive the value sent by the channel.
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
ch := make(chan bool)
// ch := make(chan bool, 1); a buffered channel
go func() {
time.Sleep(1 * time.Second)
ch <- true <-- // leaked goroutine
}()
select {
case <-ctx.Done():
fmt.Println("ctx done")
case <-ch:
fmt.Println("ch done")
}
}