| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- // Package run implements an actor-runner with deterministic teardown. It is
- // somewhat similar to package errgroup, except it does not require actor
- // goroutines to understand context semantics. This makes it suitable for use in
- // more circumstances; for example, goroutines which are handling connections
- // from net.Listeners, or scanning input from a closable io.Reader.
- package run
- // Group collects actors (functions) and runs them concurrently.
- // When one actor (function) returns, all actors are interrupted.
- // The zero value of a Group is useful.
- type Group struct {
- actors []actor
- }
- // Add an actor (function) to the group. Each actor must be pre-emptable by an
- // interrupt function. That is, if interrupt is invoked, execute should return.
- // Also, it must be safe to call interrupt even after execute has returned.
- //
- // The first actor (function) to return interrupts all running actors.
- // The error is passed to the interrupt functions, and is returned by Run.
- func (g *Group) Add(execute func() error, interrupt func(error)) {
- g.actors = append(g.actors, actor{execute, interrupt})
- }
- // Run all actors (functions) concurrently.
- // When the first actor returns, all others are interrupted.
- // Run only returns when all actors have exited.
- // Run returns the error returned by the first exiting actor.
- func (g *Group) Run() error {
- if len(g.actors) == 0 {
- return nil
- }
- // Run each actor.
- errors := make(chan error, len(g.actors))
- for _, a := range g.actors {
- go func(a actor) {
- errors <- a.execute()
- }(a)
- }
- // Wait for the first actor to stop.
- err := <-errors
- // Signal all actors to stop.
- for _, a := range g.actors {
- a.interrupt(err)
- }
- // Wait for all actors to stop.
- for i := 1; i < cap(errors); i++ {
- <-errors
- }
- // Return the original error.
- return err
- }
- type actor struct {
- execute func() error
- interrupt func(error)
- }
|