diff options
Diffstat (limited to 'vendor/github.com/oklog/run/group.go')
-rw-r--r-- | vendor/github.com/oklog/run/group.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/vendor/github.com/oklog/run/group.go b/vendor/github.com/oklog/run/group.go new file mode 100644 index 0000000..832d47d --- /dev/null +++ b/vendor/github.com/oklog/run/group.go | |||
@@ -0,0 +1,62 @@ | |||
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 | } | ||