In this example we are going to run a goroutine and wait for it to finish its job. However, we only allow it to finish its job in maximum 3 seconds. If takes longer, we are going to force it to timeout. For that we are going to use context.WithTimeout feature.


Example


package main

import (
"context"
"fmt"
"math/rand"
"time"
)

func main() {
fmt.Println(">>>>> BEGIN")

ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
// Cancel even if everything goes fine without an error to release resources.
defer cancel()

ch := make(chan int)

go doSomething(ch)

select {
case <-ctx.Done():
fmt.Println("TIMEOUT:", ctx.Err())
case t := <-ch:
fmt.Printf("JOB DONE in %d seconds\n", t)
}

fmt.Println(">>>>> END")
}

func doSomething(ch chan<- int) {
// Prevent picking up the same random number all the time for sleeping.
rand.Seed(time.Now().UnixNano())

// Pick a random number to simulate time it takes to finish the job.
delay := rand.Intn(5)
fmt.Printf("RUN: %d seconds\n", delay)
time.Sleep(time.Duration(delay) * time.Second)

ch<- delay
}

Test


>>>>> BEGIN
RUN: 1 seconds
JOB DONE in 1 seconds
>>>>> END

>>>>> BEGIN
RUN: 4 seconds
TIMEOUT: context deadline exceeded
>>>>> END

>>>>> BEGIN
RUN: 5 seconds
TIMEOUT: context deadline exceeded
>>>>> END

>>>>> BEGIN
RUN: 3 seconds
JOB DONE in 3 seconds
>>>>> END