Go by Example

Non-Blocking Channel Operations

Use select with a default case to attempt a channel send or receive without blocking.

A select with a default case tries a channel operation and continues immediately if that operation cannot proceed. It is useful when the caller can choose to drop or defer work instead of waiting.

The send succeeds only if the one-slot buffer has room. The receive succeeds only if a value is ready.

package main
 
import "fmt"
 
func main() {
    messages := make(chan string, 1)
    select {
    case messages <- "event":
        fmt.Println("sent")
    default:
        fmt.Println("buffer full")
    }
    select {
    case message := <-messages:
        fmt.Println("received:", message)
    default:
        fmt.Println("no message")
    }
}

In production

A non-blocking send can drop metrics or best-effort events when a consumer is slow. Make that loss visible with a counter. For work that must complete, use a bounded queue and apply backpressure instead of silently discarding it.

Enjoyed this? Get more software craft delivered to your inbox.