run: github.com/oklog/run Index | Examples | Files

package run

import "github.com/oklog/run"

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.

Index

Examples

Package Files

group.go

type Group Uses

type Group struct {
    // contains filtered or unexported fields
}

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.

func (*Group) Add Uses

func (g *Group) Add(execute func() error, interrupt func(error))

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.

Code:

var g run.Group
{
    cancel := make(chan struct{})
    g.Add(func() error {
        select {
        case <-time.After(time.Second):
            fmt.Printf("The first actor had its time elapsed\n")
            return nil
        case <-cancel:
            fmt.Printf("The first actor was canceled\n")
            return nil
        }
    }, func(err error) {
        fmt.Printf("The first actor was interrupted with: %v\n", err)
        close(cancel)
    })
}
{
    g.Add(func() error {
        fmt.Printf("The second actor is returning immediately\n")
        return errors.New("immediate teardown")
    }, func(err error) {
        // Note that this interrupt function is called, even though the
        // corresponding execute function has already returned.
        fmt.Printf("The second actor was interrupted with: %v\n", err)
    })
}
fmt.Printf("The group was terminated with: %v\n", g.Run())

Output:

The second actor is returning immediately
The first actor was interrupted with: immediate teardown
The second actor was interrupted with: immediate teardown
The first actor was canceled
The group was terminated with: immediate teardown

Code:

ctx, cancel := context.WithCancel(context.Background())
var g run.Group
{
    ctx, cancel := context.WithCancel(ctx) // note: shadowed
    g.Add(func() error {
        return runUntilCanceled(ctx)
    }, func(error) {
        cancel()
    })
}
go cancel()
fmt.Printf("The group was terminated with: %v\n", g.Run())

Output:

The group was terminated with: context canceled

Code:

var g run.Group
{
    ln, _ := net.Listen("tcp", ":0")
    g.Add(func() error {
        defer fmt.Printf("http.Serve returned\n")
        return http.Serve(ln, http.NewServeMux())
    }, func(error) {
        ln.Close()
    })
}
{
    g.Add(func() error {
        return errors.New("immediate teardown")
    }, func(error) {
        //
    })
}
fmt.Printf("The group was terminated with: %v\n", g.Run())

Output:

http.Serve returned
The group was terminated with: immediate teardown

func (*Group) Run Uses

func (g *Group) Run() error

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.

Package run is imported by 15 packages. Updated 2018-06-03. Refresh now. Tools for package owners.