Merge pull request #10544 from ndeloof/parallel_race

fix race condition when --parallel is used with a large number of dependent services
This commit is contained in:
Guillaume Lours 2023-05-10 11:50:59 +02:00 committed by GitHub
commit 3b32a264c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 27 additions and 12 deletions

View File

@ -97,19 +97,37 @@ func InReverseDependencyOrder(ctx context.Context, project *types.Project, fn fu
} }
func (t *graphTraversal) visit(ctx context.Context, g *Graph) error { func (t *graphTraversal) visit(ctx context.Context, g *Graph) error {
nodes := t.extremityNodesFn(g) expect := len(g.Vertices)
if expect == 0 {
return nil
}
eg, ctx := errgroup.WithContext(ctx) eg, ctx := errgroup.WithContext(ctx)
if t.maxConcurrency > 0 { if t.maxConcurrency > 0 {
eg.SetLimit(t.maxConcurrency) eg.SetLimit(t.maxConcurrency + 1)
} }
t.run(ctx, g, eg, nodes) nodeCh := make(chan *Vertex)
eg.Go(func() error {
for node := range nodeCh {
expect--
if expect == 0 {
close(nodeCh)
return nil
}
t.run(ctx, g, eg, t.adjacentNodesFn(node), nodeCh)
}
return nil
})
return eg.Wait() nodes := t.extremityNodesFn(g)
t.run(ctx, g, eg, nodes, nodeCh)
err := eg.Wait()
return err
} }
// Note: this could be `graph.walk` or whatever // Note: this could be `graph.walk` or whatever
func (t *graphTraversal) run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex) { func (t *graphTraversal) run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex, nodeCh chan *Vertex) {
for _, node := range nodes { for _, node := range nodes {
// Don't start this service yet if all of its children have // Don't start this service yet if all of its children have
// not been started yet. // not been started yet.
@ -125,14 +143,11 @@ func (t *graphTraversal) run(ctx context.Context, graph *Graph, eg *errgroup.Gro
eg.Go(func() error { eg.Go(func() error {
err := t.visitorFn(ctx, node.Service) err := t.visitorFn(ctx, node.Service)
if err != nil { if err == nil {
return err
}
graph.UpdateStatus(node.Key, t.targetServiceStatus) graph.UpdateStatus(node.Key, t.targetServiceStatus)
}
t.run(ctx, graph, eg, t.adjacentNodesFn(node)) nodeCh <- node
return nil return err
}) })
} }
} }