]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/oklog/run/group.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / oklog / run / group.go
1 // Package run implements an actor-runner with deterministic teardown. It is
2 // somewhat similar to package errgroup, except it does not require actor
3 // goroutines to understand context semantics. This makes it suitable for use in
4 // more circumstances; for example, goroutines which are handling connections
5 // from net.Listeners, or scanning input from a closable io.Reader.
6 package run
7
8 // Group collects actors (functions) and runs them concurrently.
9 // When one actor (function) returns, all actors are interrupted.
10 // The zero value of a Group is useful.
11 type Group struct {
12 actors []actor
13 }
14
15 // Add an actor (function) to the group. Each actor must be pre-emptable by an
16 // interrupt function. That is, if interrupt is invoked, execute should return.
17 // Also, it must be safe to call interrupt even after execute has returned.
18 //
19 // The first actor (function) to return interrupts all running actors.
20 // The error is passed to the interrupt functions, and is returned by Run.
21 func (g *Group) Add(execute func() error, interrupt func(error)) {
22 g.actors = append(g.actors, actor{execute, interrupt})
23 }
24
25 // Run all actors (functions) concurrently.
26 // When the first actor returns, all others are interrupted.
27 // Run only returns when all actors have exited.
28 // Run returns the error returned by the first exiting actor.
29 func (g *Group) Run() error {
30 if len(g.actors) == 0 {
31 return nil
32 }
33
34 // Run each actor.
35 errors := make(chan error, len(g.actors))
36 for _, a := range g.actors {
37 go func(a actor) {
38 errors <- a.execute()
39 }(a)
40 }
41
42 // Wait for the first actor to stop.
43 err := <-errors
44
45 // Signal all actors to stop.
46 for _, a := range g.actors {
47 a.interrupt(err)
48 }
49
50 // Wait for all actors to stop.
51 for i := 1; i < cap(errors); i++ {
52 <-errors
53 }
54
55 // Return the original error.
56 return err
57 }
58
59 type actor struct {
60 execute func() error
61 interrupt func(error)
62 }