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!