Function calls and goroutines cannot be terminated from the caller, the functions and goroutines have to support the cancellation, often via a context.Context
value or a done
channel.
In either case, the functions are responsible to check / monitor the context, and if cancel is requested (when the Context’s done channel is closed), return early. There isn’t an easier / automatic way.
If the task executes code in a loop, a convenient solution is to check the done channel in each iteration, and return if it’s closed. If the task is one “monolith”, the implementor is responsible to use / insert “checkpoints” at which the task can be reasonably aborted early if such cancellation is requested.
An easy way to check if the done channel is closed is to use a non-blocking select
, such as:
select {
case <-ctx.Done():
// Abort / return early
return
default:
}
Care must be taken when the task uses other channel operations, as they may block in a nondeterministic way. Those selects should include the ctx.Done()
channel too:
select {
case v := <- someChannel:
// Do something with v
case <-ctx.Done():
// Abort / return early
return
}
Also be careful, because if the above receive from someChannel
never blocks there is no guarantee a cancellation is properly handled, because if multiple communications can proceed in a select
, one is chosen randomly (and there’s no guarantee the <-ctx.Done()
is ever chosen). In such case you may combine the above 2: first do a non-blocking check for cancellation, then use a select
with your channel operations and the cancel monitoring.