loop

package
v0.0.0-...-68847cf Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2023 License: BSD-3-Clause Imports: 4 Imported by: 0

Documentation

Overview

Package loop supports the developer implementing the typical Go idiom for concurrent applications running a loop selecting data from channels in a backend goroutine. Stopping those loops or getting aware of internal errors requires extra efforts. The loop package helps to control this kind of goroutines.

type Printer struct {
	prints chan string
	loop   loop.Loop
}

func NewPrinter(ctx context.Context) (*Printer, error) {
	p := &Printer{
		ctx:    ctx,
		prints: make(chan string),
	}
	l, err := loop.Go(
		p.backend,
		loop.WithContext(ctx),
		loop.WithFinalizer(func(err error) error {
			...
		})
	if err != nil {
		return nil, err
	}
	p.loop = l
	return p, nil
}

func (p *printer) backend(ctx context.Context) error {
	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case str := <-p.prints:
			println(str)
	}
}

The backend here now can be stopped with p.loop.Stop() returning a possible internal error. Also recovering of internal panics with a repairer function passed as option is possible. See the code examples.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Finalizer

type Finalizer func(err error) error

Finalizer is called with the final error if the backend loop terminates.

type Loop

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

Loop manages running for-select-loops in the background as goroutines in a controlled way. Users can get information about status and possible failure as well as control how to stop, restart, or recover via options.

func Go

func Go(worker Worker, options ...Option) (*Loop, error)

Go starts a loop running the given worker with the given options.

func (*Loop) Err

func (l *Loop) Err() error

Err returns information about a possible error of the Loop.

func (*Loop) Status

func (l *Loop) Status() Status

Status returns the current status of the Loop.

func (*Loop) Stop

func (l *Loop) Stop()

Stop terminates the Loop backend. It works asynchronous as the goroutine may need time for cleanup. Anyone wanting to be notified on state has to handle it in a Finalizer.

type Option

type Option func(loop *Loop) error

Option defines the signature of an option setting function.

func WithContext

func WithContext(ctx context.Context) Option

WithContext allows to pass a context for cancellation or timeout.

func WithFinalizer

func WithFinalizer(finalizer Finalizer) Option

WithFinalizer sets a function for finalizing the work of a Loop.

func WithRepairer

func WithRepairer(repairer Repairer) Option

WithRepairer defines the panic handler of a loop.

type Repairer

type Repairer func(reason interface{}) error

Repairer allows the loop goroutine to react on a panic during its work. Returning a nil the loop will be continued by calling the worker again.

Example

ExampleRepairer demonstrates the usage of a repairer.

panics := make(chan string)
// Sample loop worker.
worker := func(ctx context.Context) error {
	for {
		select {
		case <-ctx.Done():
			return nil
		case str := <-panics:
			panic(str)
		}
	}
}
// Repairer function checks the reasion. "never mind" will
// be repaired, all others lead to an error. The repairer
// is also responsable for fixing the owners state crashed
// during panic.
repairer := func(reason interface{}) error {
	why := reason.(string)
	if why == "never mind" {
		return nil
	}
	return fmt.Errorf("worker panic: %v", why)
}
l, err := loop.Go(worker, loop.WithRepairer(repairer))
if err != nil {
	panic(err)
}
l.Stop()

type Status

type Status int

Status defines the status of a loop.

const (
	StatusStopped Status = iota
	StatusStarting
	StatusWorking
	StatusRepairing
	StatusStopping
	StatusFinalizing
	StatusError
)

type Worker

type Worker func(ctx context.Context) error

Worker discribes the backend function running the loop.

Example

ExampleWorker shows the usage of Loop with no repairer. The inner loop contains a select listening to the channel returned by Closer.Done(). Other channels are for the standard communication with the Loop.

prints := make(chan string)
ctx, cancel := context.WithCancel(context.Background())
// Sample loop worker.
worker := func(ctx context.Context) error {
	for {
		select {
		case <-ctx.Done():
			// We shall stop.
			return ctx.Err()
		case str := <-prints:
			// Standard work of example loop.
			if str == "panic" {
				return errors.New("panic")
			}
			println(str)
		}
	}
}
l, err := loop.Go(worker, loop.WithContext(ctx))
if err != nil {
	panic(err)
}

prints <- "Hello"
prints <- "World"

// cancel() terminates the loop via the context.
cancel()

// Returned error must be nil in this example.
if l.Err() != nil {
	panic(l.Err())
}

Jump to

Keyboard shortcuts

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