In the following code, how can I add proper timeout error handling in case one of the launched go routines takes too long (e.g. > 10 sec) to finish? Note, that I do not want to have an "overall" timeout but a timeout for each go routine, so that I can also know which go routine timed out in my error report.
var wg sync.WaitGroup
for _, element:= range elements{
wg.Add(1)
go doWork(element, &wg)
}
wg.Wait()
kind regards
You can use Context, in the following way:
func doWork(ctx context.Context, element Element, wg &sync.WaitGroup) {
defer wg.Done()
done := make(chan struct{})
go func() {
// do some work on element
done <- struct{}{} // signal work is done
}
select {
case <- done:
{
// work completed in time
}
case <- ctx.Done:
{
// timeout reached
}
}
}
contexts := make([]*context.Context, len(elements))
for _, element:= range elements{
wg.Add(1)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
contexts = append(contexts, ctx)
go doWork(ctx, element, &wg)
}
wg.Wait()
for i, ctx := range contexts {
if ctx.Err() {
fmt.Println("Go routine ", i, "canceled due to", ctx.Err())
}
}
nice way is to use context.WithDeadline
:
// WithDeadline returns a copy of the parent context with the deadline adjusted // to be no later than d. If the parent's deadline is already earlier than d, // WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should // call cancel as soon as the operations running in this Context complete.
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
// Even though ctx will be expired, it is good practice to call its
// cancelation function in any case. Failure to do so may keep the
// context and its parent alive longer than necessary.
defer cancel()
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With