| 130 | } |
| 131 | |
| 132 | func (t *graphTraversal) visit(ctx context.Context, g *Graph) error { |
| 133 | expect := len(g.Vertices) |
| 134 | if expect == 0 { |
| 135 | return nil |
| 136 | } |
| 137 | |
| 138 | eg, ctx := errgroup.WithContext(ctx) |
| 139 | if t.maxConcurrency > 0 { |
| 140 | eg.SetLimit(t.maxConcurrency + 1) |
| 141 | } |
| 142 | nodeCh := make(chan *Vertex, expect) |
| 143 | defer close(nodeCh) |
| 144 | // nodeCh need to allow n=expect writers while reader goroutine could have returner after ctx.Done |
| 145 | eg.Go(func() error { |
| 146 | for { |
| 147 | select { |
| 148 | case <-ctx.Done(): |
| 149 | return nil |
| 150 | case node := <-nodeCh: |
| 151 | expect-- |
| 152 | if expect == 0 { |
| 153 | return nil |
| 154 | } |
| 155 | t.run(ctx, g, eg, t.adjacentNodesFn(node), nodeCh) |
| 156 | } |
| 157 | } |
| 158 | }) |
| 159 | |
| 160 | nodes := t.extremityNodesFn(g) |
| 161 | t.run(ctx, g, eg, nodes, nodeCh) |
| 162 | |
| 163 | return eg.Wait() |
| 164 | } |
| 165 | |
| 166 | // Note: this could be `graph.walk` or whatever |
| 167 | func (t *graphTraversal) run(ctx context.Context, graph *Graph, eg *errgroup.Group, nodes []*Vertex, nodeCh chan *Vertex) { |