Documentation ¶
Overview ¶
Package async has helper utilities for running async code with proper tracing.
When starting go routines, use async.Run:
// this starts a go routine async.Run(ctx, async.Func(func(ctx context.Context) error { ctx = trace.StartCall(ctx, "...") defer trace.EndCall(ctx) .... do whatever needs to be done ... .... just return error to abort loop .... }))
If the long running activity involves fetching from a reader or some other iterative pattern, use async.Loop
// this starts a go routine async.Loop(ctx, async.Func(func(ctx context.Context) error { ctx = trace.StartCall(ctx, "...") defer trace.EndCall(ctx) .... do whatever... return errors to abort loop ... maybe async.Sleep(ctx, time.Minute) }))
Note: async.Loop terminates the loop when the inner function returns an error or the context is canceled.
To wait for all go-routines to terminate, use Tasks.Wait. See examples for using Tasks
Index ¶
- Variables
- func Loop(ctx context.Context, r Runner)
- func Run(ctx context.Context, r Runner)
- func RunBackground(_ context.Context, r Runner)deprecated
- func RunClose(ctx context.Context, r Runner) error
- func Sleep(ctx context.Context, duration time.Duration)
- func SleepUntil(ctx context.Context, deadline time.Time)
- type Closer
- type Func
- type MutexWithContext
- type RetryableOnce
- type Runner
- type Tasks
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var Default = NewTasks("async.run")
Default is the default runner
Functions ¶
func Loop ¶
Loop repeatedly executes the provided task until it returns false or the context is canceled.
Example ¶
package main import ( "context" "fmt" "time" "github.com/getoutreach/gobox/pkg/async" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() count := 0 async.Loop(ctx, async.Func(func(ctx context.Context) error { if count < 3 { count++ fmt.Println("count", count) } else { <-ctx.Done() } return nil })) time.Sleep(time.Millisecond * 5) cancel() async.Default.Wait() }
Output: count 1 count 2 count 3
func Run ¶
Run executes a single asynchronous task.
It creates a new trace for the task and passes through deadlines.
func RunBackground
deprecated
Types ¶
type Closer ¶ added in v1.36.0
Closer is the interface for closing a runner function. Implement this for cleaning up things.
type MutexWithContext ¶
type MutexWithContext struct {
// contains filtered or unexported fields
}
MutexWithContext is a lock that supports context cancellation.
Note that unlike the `sync.Locker` style of mutex, this one's `Lock` method can fail and you must check its return value.
func NewMutexWithContext ¶
func NewMutexWithContext() *MutexWithContext
NewMutexWithContext creates a new MutexWithContext instance.
func (*MutexWithContext) Lock ¶
func (m *MutexWithContext) Lock(ctx context.Context) error
Lock acquires the mutex, blocking if it is unavailable.
Unlike `sync.Mutex.Lock()`, this function can fail. It is responsibility of the caller to check the returned error and not proceed if it is non-nil.
func (*MutexWithContext) Unlock ¶
func (m *MutexWithContext) Unlock()
Unlock releases the mutex, allowing the next waiter to proceed.
type RetryableOnce ¶ added in v1.95.1
type RetryableOnce struct {
// contains filtered or unexported fields
}
RetryableOnce is modified from sync.Once with a tweak to allow retry
func (*RetryableOnce) Do ¶ added in v1.95.1
func (o *RetryableOnce) Do(f func() bool) bool
Do calls the function f if and only if one of the following of two cases 1. Do is being called for the first time for this instance of RetryableOnce 2. Do has been called multiple times before and f returns false in all those calls.
If f panics, Do considers it as "done"; future calls of Do return without calling f. This function return true when future calls of Do will no longer call f
type Tasks ¶
Tasks runs tasks
Example (Loop) ¶
package main import ( "context" "fmt" "time" "github.com/getoutreach/gobox/pkg/async" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() count := 0 tasks := async.Tasks{Name: "example"} tasks.Loop(ctx, async.Func(func(ctx context.Context) error { if count < 3 { count++ fmt.Println("count", count) } else { <-ctx.Done() } return nil })) async.Sleep(ctx, time.Millisecond*5) cancel() tasks.Wait() }
Output: count 1 count 2 count 3
Example (Run) ¶
package main import ( "context" "fmt" "github.com/getoutreach/gobox/pkg/async" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() tasks := async.Tasks{Name: "example"} tasks.Run(ctx, async.Func(func(ctx context.Context) error { fmt.Println("Run example") return nil })) cancel() tasks.Wait() }
Output: Run example
Example (RunBackground) ¶
package main import ( "context" "fmt" "github.com/getoutreach/gobox/pkg/async" ) func main() { ctxMain, cancel := context.WithCancel(context.Background()) async.RunBackground(ctxMain, async.Func(func(ctx context.Context) error { // the task is expected to run with background context // cancel the context passed into RunBackground() function should not // propagate to the context used by async.Func() cancel() fmt.Println(ctx.Err()) fmt.Println("Run example") return nil })) async.Default.Wait() }
Output: <nil> Run example