Package introduction context.WithTimeout
In the previous article we learned context.WithCancel where we manually send the cancel signal from context. But we can also add cancel signal to context automatically by using timeout timings. By using timeout, we no longer need to manually call cancel execution, but with timeout cancel will be automatically executed if the timeout time has passed.
Why should we use context?
Using context with timeout is perfect when we query a database or http api, but want to specify a maximum timeout. When creating a context with an automatic cancel signal using timeout, we can use the context.WithTimeout(parent,duration) function.
The benefit of using context.WithTimeout is that when we will execute a function, when the function executes for a certain period of time that passes the timeout limit, the process will be automatically canceled. This happens so that the process that takes a long time does not become a * blocker* for the next processes.
Implementation and sample
We will now try to implement context.WithTimeout. We will use this method to restrict access to a function based on a certain time limit. Further, we will try to directly study the program code below.
func main() {
fmt.Println("Total Goroutines : ", runtime.NumGoroutine())
parent := context.Background()
ctx, cancel := context.WithTimeout(parent, 5*time.Second)
defer cancel()
destination := CreateCounterWithTimeout(ctx)
fmt.Println("Total Goroutine : ", runtime.NumGoroutine())
for n := range destination {
fmt.Println("Counter : ", n)
}
fmt.Println("Total Goroutines : ", runtime.NumGoroutine())
}
func CreateCounterWithTimeout(ctx context.Context) chan int {
destination := make(chan int)
go func() {
defer close(destination)
counter := 1
for {
select {
case < ctx.Done():
return
default:
destination <- counter
counter++
time.Sleep(1 * time.Second) // simulate slow process
}
}
}()
return destination
}
The above program actually modifies the previous function that we learned in context.WithCancel. The difference from the previous article is the use of context of course and the use of defer cancel()
which in the previous article we will call and execute the cancel()
function manually.
Here is the result of the program when it is run below.
✗ go run main.go
Total Goroutines: 1
Total Goroutines : 2
Counters: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
Total Goroutines: 1
It can be seen that the program results in a total of one initialization goroutine and then when executing the (CreateCounterWithTiemout* function it will increase the goroutine to two and the function immediately prints a counter with the process time of each counter is one second. Then the counter will issue 5 counters because the context sent to the goroutine function is only limited to 5 seconds which each process takes one second so the function process will print only 5 counters. Then it will exit the process and automatically cancel the context because it has exceeded the time limit and the goroutine will be deleted and it is evident that the total goroutine afterwards will return to one gorutine.
Conclusion
context.WithTimeout is a very useful method when we have a process function that is not certain that the process will be completed within a certain time limit. To avoid waiting too long for the result of an api or response from the process, we need to limit the process so that it does not become a * blocker* with a timeout time limit unit so that the process will be completed or fail our program will still have a process that is not too long according to the tolerance that we have determined the time process.