On May 25, 2021 I learned

  • Go
  • Slices in Go are passed by reference (I’m a fool)
  • You can subtly leak Go routines by not cancelling a context and awaiting context cancellation if using an unbuffered channel.
package main

import (
	"context"
	"fmt"
	"runtime"
	"time"
)

func longOp() string {
	time.Sleep(2 * time.Second)
	return "response"
}

func main() {
	ctx := context.Background()
	// the context will never be cancelled

    // non-buffered channel will block writers if there are no readers
	data := make(chan string)

	go func() {
		select {
		case <-ctx.Done():
			fmt.Println("Timeout")
		case data <- longOp():
		}
	}()

	select {
	case <-time.After(1 * time.Second):
		fmt.Println("timeout")
	case val := <-data:
		fmt.Println("Success " + val)
	}
    // no readers at this point

	time.Sleep(2 * time.Second)
	fmt.Println(runtime.NumGoroutine()) // oops
}