Documentation ¶
Overview ¶
The package defines a single interface and a few implementations of the interface. The externalization of the loop flow control makes it easy to test the internal functions of background goroutines by, for instance, only running the loop once while under test.
The design is that any errors which need to be returned from the loop will be passed back on a channel whose implementation is left up to the individual Looper. Calling methods can wait on execution and for any resulting errors by calling the Wait() method on the Looper.
Example ¶
In this example, we are going to run a FreeLooper with 5 iterations. In the course of running, an error is generated, which the parent function captures and outputs. As a result of the error only 3 of the 5 iterations are completed and the output reflects this.
looper := NewFreeLooper(5, make(chan error)) runner := func(looper Looper) { x := 0 looper.Loop(func() error { fmt.Println(x) x++ if x == 3 { return errors.New("Uh oh") } return nil }) } go runner(looper) err := looper.Wait() if err != nil { fmt.Printf("I got an error: %s\n", err.Error()) }
Output: 0 1 2 I got an error: Uh oh
Index ¶
Examples ¶
Constants ¶
const ( FOREVER = -1 ONCE = 1 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type FreeLooper ¶
A FreeLooper is like a TimedLooper but doesn't wait between iterations.
func NewFreeLooper ¶
func NewFreeLooper(count int, done chan error) *FreeLooper
func (*FreeLooper) Done ¶
func (l *FreeLooper) Done(err error)
This is used internally, but can also be used by controlling routines to signal that a job is completed. The FreeLooper doesn's support its use outside the internals.
func (*FreeLooper) Loop ¶
func (l *FreeLooper) Loop(fn func() error)
func (*FreeLooper) Quit ¶
func (l *FreeLooper) Quit()
Quit() signals to the Looper to not run the next iteration and to call Done() and return as quickly as possible. It is does not intervene between iterations. It is a non-blocking operation.
func (*FreeLooper) Wait ¶
func (l *FreeLooper) Wait() error
func (*FreeLooper) WaitWithoutError ¶
func (l *FreeLooper) WaitWithoutError()
type Looper ¶
type Looper interface { Loop(fn func() error) Wait() error WaitWithoutError() Done(err error) Quit() }
A Looper is used in place of a direct call to "for {}" and implements some controls over how the loop will be run. The Loop() function is the main call used by dependant routines. Common patterns like Quit and Done channels are easily implemented in a Looper.
type TimedLooper ¶
type TimedLooper struct { Count int Interval time.Duration DoneChan chan error Immediate bool // contains filtered or unexported fields }
A TimedLooper is a Looper that runs on a timed schedule, using a Timer underneath. It also implements Quit and Done channels to allow external routines to more easily control and synchronize the loop.
If you pass in a DoneChan at creation time, it will send a nil on the channel when the loop has completed successfully or an error if the loop resulted in an error condition.
Example ¶
In this example, we run a really fast TimedLooper for a fixed number of runs.
looper := NewTimedLooper(5, 1*time.Nanosecond, make(chan error)) runner := func(looper Looper) { x := 0 looper.Loop(func() error { fmt.Println(x) x++ return nil }) } go runner(looper) err := looper.Wait() if err != nil { fmt.Printf("I got an error: %s\n", err.Error()) }
Output: 0 1 2 3 4
func NewImmediateTimedLooper ¶
func NewImmediateTimedLooper(count int, interval time.Duration, done chan error) *TimedLooper
Same as a TimedLooper, except it will execute an iteration of the loop immediately after calling on Loop() (as opposed to waiting until the tick)
func NewTimedLooper ¶
func NewTimedLooper(count int, interval time.Duration, done chan error) *TimedLooper
func (*TimedLooper) Done ¶
func (l *TimedLooper) Done(err error)
Signal a dependant routine that we're done with our work
func (*TimedLooper) Loop ¶
func (l *TimedLooper) Loop(fn func() error)
The main method of the Looper. This call takes a function with a single return value, an error. If the error is nil, the Looper will run the next iteration. If it's an error, it will not run the next iteration, will clean up any internals that need to be, and will invoke done().
func (*TimedLooper) Quit ¶
func (l *TimedLooper) Quit()
Quit() signals to the Looper to not run the next iteration and to call done() and return as quickly as possible. It is does not intervene between iterations.
Example ¶
In this example we run a really fast TimedLooper for a fixed number of runs, but we interrupt it with a Quit() call so it only completes one run.
looper := NewTimedLooper(5, 50*time.Millisecond, make(chan error)) runner := func(looper Looper) { x := 0 looper.Loop(func() error { fmt.Println(x) x++ return nil }) } go runner(looper) // Wait for one run to complete time.Sleep(90 * time.Millisecond) looper.Quit() err := looper.Wait() if err != nil { fmt.Printf("I got an error: %s\n", err.Error()) }
Output: 0
func (*TimedLooper) Wait ¶
func (l *TimedLooper) Wait() error
func (*TimedLooper) WaitWithoutError ¶
func (l *TimedLooper) WaitWithoutError()
WaitWithoutError, unlike Wait(), can be waited on by multiple goroutine safely. It does not, however, return the last error.