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 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.
type Option ¶
Option defines the signature of an option setting function.
func WithContext ¶
WithContext allows to pass a context for cancellation or timeout.
func WithFinalizer ¶
WithFinalizer sets a function for finalizing the work of a Loop.
func WithRepairer ¶
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 Worker ¶
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())
}