The other day I ran into a situation where I wanted my function to block until it received data from a Go channel. But I didn’t want it to block indefinitely. I wanted it to timeout after a few seconds if it didn’t get any data.

My coworker Dan showed me a technique I didn’t know about to easily accomplish this. It wasn’t surprising to learn how easy it was, given that Go has strong support for concurrency out the gate.

package main

import (
    "fmt"
    "time"
)

func doSomething(ch chan string) {
    time.Sleep(2 * time.Second)
    ch <- "foo"
}

func main() {
    fmt.Println("Start.")
    defer fmt.Println("Done.")

    ch := make(chan string) // make unbuffered channel

    go doSomething(ch) // create goroutine and run function within it

    select {
    case val := <-ch: // block, waiting for value from channel
        fmt.Println("Got value from channel:", val)
    case <-time.After(1 * time.Second): // timeout after X seconds
        fmt.Println("Timed out!")
    }
}

Running this shows:

Start.
Timed out!
Done.

Simple and elegant!