简体   繁体   English

嵌套在一堆 goroutine 中的 errgroup

[英]Nested errgroup inside bunch of goroutines

I am fairly new to golang and its concurrency principles.我对 golang 及其并发原则相当陌生。 My use-case involves performing multiple http requests(for a single entity), on batch of entities.我的用例涉及对一批实体执行多个 http 请求(针对单个实体)。 If any of the http request fails for an entity, I need to stop all parallel http requests for it.如果对实体的任何 http 请求失败,我需要停止所有并行的 http 请求。 Also, I have to manage counts of entities failed with errors.此外,我必须管理因错误而失败的实体的数量。 I am trying to implement errorgroup inside entities goroutines, such that if any http request fails for a single entity the errorgroup terminates and return error to its parent goroutine.我正在尝试在实体 goroutine 中实现 errorgroup,这样如果任何 http 请求对单个实体失败,则 errorgroup 将终止并将错误返回到其父 goroutine。 But I am not sure how to maintain count of errors.但我不确定如何保持错误计数。

func main(entity[] string) {
    errorC := make(chan string) // channel to insert failed entity
    var wg sync.WaitGroup

    for _, link := range entity {
        wg.Add(1)
        // Spawn errorgroup here. errorgroup_spawn
    }

    go func() {
        wg.Wait()   
        close(errorC)    
    }()

    for msg := range errorC {
        // here storing error entityIds somewhere.
    }
}

and errorgroup like this和这样的错误组

func errorgroup_spawn(ctx context.Context, errorC chan string, wg *sync.WaitGroup) { // and other params
    defer (*wg).Done()
    
   goRoutineCollection, ctxx := errgroup.WithContext(ctx)
    results := make(chan *result)
    goRoutineCollection.Go(func() error {
        // http calls for single entity
        // if error occurs, push it in errorC, and return Error.
        return nil
    })

    go func() {
        goRoutineCollection.Wait()
        close(result)
    }()

   return goRoutineCollection.Wait()
}

PS: I was also thinking to apply nested errorgroups, but can't think to maintain error counts, while running other errorgroups Can anyone guide me, is this a correct approach to handle such real world scenarios? PS:我也在考虑应用嵌套的错误组,但在运行其他错误组时无法考虑维护错误计数任何人都可以指导我,这是处理此类现实世界场景的正确方法吗?

One way to keep track of errors is to use a status struct to keep track of which error came from where:跟踪错误的一种方法是使用状态结构来跟踪哪个错误来自何处:

type Status struct {
   Entity string
   Err error
}
...

errorC := make(chan Status) 

// Spawn error groups with name of the entity, and when error happens, push Status{Entity:entityName,Err:err} to the chanel

You can then read all errors from the error channel and figure out what failed why.然后,您可以从错误通道中读取所有错误并找出失败的原因。

Another option is not to use errorgroups at all.另一种选择是根本不使用错误组。 This makes things more explicit, but whether it is better or not is debatable:这使事情更加明确,但它是否更好是值得商榷的:

// Keep entity statuses
statuses:=make([]Status,len(entity))
for i, link := range entity {
   statuses[i].Entity=link
   wg.Add(1)
   go func(i index) {
      defer wg.Done()
      ctx, cancel:=context.WithCancel(context.Background())
      defer cancel()

      // Error collector
      status:=make(chan error)
      defer close(status)
      go func() {
         for st:=range status {
             if st!=nil {
                cancel()  // Stop all calls 
                // store first error
                if statuses[i].Err==nil {
                   statuses[i].Err=st
                }
             }
         }
      }()

      innerWg:=sync.WaitGroup{}
      innerWg.Add(1)
      go func() {
         defer innerWg.Done()
         status<- makeHttpCall(ctx)
      }()
      innerWg.Add(1)
      go func() {
         defer innerWg.Done()
         status<- makeHttpCall(ctx)
      }()
      ...
      innerWg.Wait()

   }(i)
}

When everything is done, statuses will contain all entities and corresponding statuses.一切完成后, statuses将包含所有实体和相应的状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM