Trying to understand how go context cancellation will abort execution of subsequent code
Details of experiment:
2sec
sum
in a separate go-routine - which sleeps for 1sec
for test-run-1 & 4sec
for test-run-23sec
to let spun go-routine complete executionpackage main
import (
"context"
"fmt"
"log"
"time"
)
func main() {
c := context.Background()
childCtx, cancel := context.WithTimeout(c, 2*time.Second)
defer cancel()
ch := make(chan int, 1)
go sum(5, 6, ch)
var msg string
select {
case <-childCtx.Done():
msg = "return from ctx done channel"
case res := <-ch:
msg = fmt.Sprintf("return from go routine: %v", res)
}
log.Print(msg)
time.Sleep(3 * time.Second) //sleeping here to test if go-routine is still running
}
func sum(x int, y int, c chan<- int) {
time.Sleep(1 * time.Second)
//testcase-1: sleep - 1s
//testcase-2: sleep - 4s
result := x + y
log.Printf("print from sum fn: %v", result)
c <- result
}
Response for testcase-1 : sleep sum function for 1 sec:
2021/04/12 01:06:58 print from sum fn: 11
2021/04/12 01:06:58 return from go routine: 11
Response for testcase-2 : sleep sum function for 4 sec:
2021/04/12 01:08:25 return from ctx done channel
2021/04/12 01:08:27 print from sum fn: 11
In testcase-2 when sum func sleeps for 4 secs, context is already cancelled by timeout after 2secs, why is it still executing the sum func in diff go-routine and printing print from sum fn: 1
?
From documentation: Canceling this context releases resources associated with it.
My assumption is that all the computation will be aborted immediately after 2 secs including the spun go-routine
Let me know how to do this right, thanks in adavance
As @AndySchweig has noted, context
signals a cancelation event, but does not enforce cancelation. It's up to any potentially blocking goroutine to do its best at trying to cancel/clean-up after it detects a cancelation.
To update your sum
function to support cancelation you could try:
// add context parameter as the first argument
// add a return error - to indicate any errors (i.e. function was interrupted due to cancelation)
func sum(ctx context.Context, x int, y int, c chan<- int) (err error) {
wait := 1 * time.Second // testcase-1
//wait := 4 * time.Second // testcase-2
// any blocking called - even sleeps - should be interruptible
select {
case <-time.After(wait):
case <-ctx.Done():
err = ctx.Err()
return
}
result := x + y
log.Printf("print from sum fn: %v", result)
select {
case c <- result:
case <-ctx.Done(): // check for ctx cancelation here - as no one may be listening on result channel
err = ctx.Err()
}
return
}