Go Em Exemplos: Timeouts

Timeouts são importantes para programas que conectam em recursos externos ou que de outra forma precisam limitar o tempo de execução. A implementação em Go é fácil e elegante graças aos recursos channels e select.

package main
import (
    "fmt"
    "time"
)
func main() {

Para este exemplo, suponha que se está executando uma chamada externa que retorna um resultado no canal c1 após 2 segundos. Note que o canal é buffered, então o send na goroutine é não bloqueante ou nonblocking, este é um padrão comum para prevenir vazamento de goroutines no caso do canal nunca ser lido.

    c1 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c1 <- "result 1"
    }()

Aqui está o select implementando o timeout. res := <-c1 aguarda o resultado e <-time.After aguarda o valor a ser enviado depois do timeout de 1 segundo. Como o select prossegue com o primeiro recebimento que está pronto, será executado o caso com timeout se a operação levar mais do que o tempo permitido de 1 segundo.

    select {
    case res := <-c1:
        fmt.Println(res)
    case <-time.After(1 * time.Second):
        fmt.Println("timeout 1")
    }

Se for permitido um timeout mais de longo de 3 segundos, então o recebimento de c2 será executado e o valor impresso.

    c2 := make(chan string, 1)
    go func() {
        time.Sleep(2 * time.Second)
        c2 <- "result 2"
    }()
    select {
    case res := <-c2:
        fmt.Println(res)
    case <-time.After(3 * time.Second):
        fmt.Println("timeout 2")
    }
}

Ao executar este programa, a primeira operação tem seu tempo esgotado e a segunda finaliza

$ go run timeouts.go 
timeout 1
result 2

Próximo exemplo: Non-Blocking Channel Operations.