[英]terminating blocking goroutines with errgroup
I have two tasks that are running in go routines.我有两个任务在 go 例程中运行。 I am using errgroup.
我正在使用错误组。 I am not sure how to use the errgroup.WithContext correctly.
我不确定如何正确使用 errgroup.WithContext。
In the following code, task1 is returning the error and I would like to terminate task2 (long running) when that happens.在下面的代码中,task1 正在返回错误,我想在发生这种情况时终止 task2(长时间运行)。 Please note that in this example time.sleep is added just to simulate my problem.
请注意,在此示例中添加 time.sleep 只是为了模拟我的问题。 In reality task1 and task2 are doing real work and does not have any sleep call.
实际上 task1 和 task2 正在做真正的工作并且没有任何睡眠呼叫。
package main
import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
"time"
)
func task1(ctx context.Context) error {
time.Sleep(5 * time.Second)
fmt.Println("first finished, pretend error happened")
return ctx.Err()
}
func task2(ctx context.Context) error {
select {
case <-ctx.Done():
fmt.Println("task 1 is finished with error")
return ctx.Err()
default:
fmt.Println("second started")
time.Sleep(50 * time.Second)
fmt.Println("second finished")
}
return nil
}
func test() (err error) {
ctx := context.Background()
g, gctx := errgroup.WithContext(ctx)
g.Go(func() error {
return task1(gctx)
})
g.Go(func() error {
return task2(gctx)
})
err = g.Wait()
if err != nil {
fmt.Println("wait done")
}
return err
}
func main() {
fmt.Println("main")
err := test()
if err != nil {
fmt.Println("main err")
fmt.Println(err.Error())
}
}
It's up to your tasks to handle context cancellation properly and not time.Sleep
inside a select.正确处理上下文取消而不是时间取决于您的任务。在
time.Sleep
中睡觉。
As stated in errgroup documentation:如 errgroup 文档中所述:
WithContext returns a new Group and an associated Context derived from ctx.
WithContext 返回一个新组和一个从 ctx 派生的关联上下文。
The derived Context is canceled the first time a function passed to Go returns a non-nil error or the first time Wait returns, whichever occurs first.
派生的上下文在第一次传递给 Go 的 function 返回非零错误或第一次 Wait 返回时被取消,以先发生者为准。
You are using error group right, but it's your context handling that needs a refactor.您正在使用错误组,但您的上下文处理需要重构。
Here is a refacor of your task 2:这是您的任务 2 的重构:
func task2(ctx context.Context) error {
errCh := make(chan bool)
go func() {
time.Sleep(50 * time.Second)
errCh <- true
}()
select {
case <-ctx.Done():
return fmt.Errorf("context done: %w", ctx.Err())
case <-errCh:
return errors.New("task 2 failed")
}
}
With such select, you wait for the first channel to emit.使用这样的 select,您等待第一个通道发射。 In this case, it is the context expiration, unless you modify time sleep to be lower.
在这种情况下,它是上下文过期,除非您将 time sleep 修改为更低。 Example playground .
示例游乐场。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.