run

package
v0.0.4-rc01 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 26, 2024 License: MIT Imports: 5 Imported by: 0

README

run

this package copy from: https://github.com/oklog/run

Documentation

Overview

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

Constants

This section is empty.

Variables

View Source
var ErrSignal = errors.New("signal error")

ErrSignal is returned by SignalHandler when a signal triggers termination.

Functions

func ContextHandler

func ContextHandler(ctx context.Context) (execute func() error, interrupt func(error))

ContextHandler returns an actor, i.e. an execute and interrupt func, that terminates when the provided context is canceled.

func SignalHandler

func SignalHandler(ctx context.Context, signals ...os.Signal) (execute func() error, interrupt func(error))

SignalHandler returns an actor, i.e. an execute and interrupt func, that terminates with ErrSignal when the process receives one of the provided signals, or with ctx.Error() when the parent context is canceled. If no signals are provided, the actor will terminate on any signal, per signal.Notify.

Types

type Group

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

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.

Example (Basic)
package main

import (
	"errors"
	"fmt"
	"time"

	"github.com/fengjx/go-halo/run"
)

func main() {
	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
Example (Context)
package main

import (
	"context"
	"fmt"

	"github.com/fengjx/go-halo/run"
)

func main() {
	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())
}

func runUntilCanceled(ctx context.Context) error {
	<-ctx.Done()
	return ctx.Err()
}
Output:

The group was terminated with: context canceled
Example (Listener)
package main

import (
	"errors"
	"fmt"
	"net"
	"net/http"

	"github.com/fengjx/go-halo/run"
)

func main() {
	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

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.

type SignalError

type SignalError struct {
	Signal os.Signal
}

SignalError is returned by the signal handler's execute function when it terminates due to a received signal.

SignalError has a design error that impacts comparison with errors.As. Callers should prefer using errors.Is(err, ErrSignal) to check for signal errors, and should only use errors.As in the rare case that they need to program against the specific os.Signal value.

func (SignalError) As

func (e SignalError) As(target interface{}) bool

As fixes a design error in the SignalError type, so that errors.As with the literal `&SignalError{}` will return true.

func (SignalError) Error

func (e SignalError) Error() string

Error implements the error interface.

It was a design error to define this method on a value receiver rather than a pointer receiver. For compatibility reasons it won't be changed.

func (SignalError) Is

func (e SignalError) Is(err error) bool

Is addresses a design error in the SignalError type, so that errors.Is with ErrSignal will return true.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL