Documentation
¶
Overview ¶
Package run runs a group of functions finitely or infinitely.
It provides synchronization, error propagation, and Context cancellation. Each function may or may not block, but they are all running synchronously. Literally, it supports following scenarios:
A function runs end-to-end without block. It's most for resource initialization with no cleanup need like configuration. Sample code: func(ctx context.Context) error { // Do whatever here and return error if applicable. // The function is unstoppable by os.Signal // unless it honors context cancellation.
return nil }
A function runs in the beginning and blocks until the end. It could be used for resource initialization and cleanup. Sample code: func(ctx context.Context) error { // Do whatever here and return error if applicable. // Use defer to clean up resources (if any) // while function returns.
<-ctx.Done() // Block until context canceled.
return nil }
A function blocks to serve external requests after initialization. It can not terminate unless another dedicate close function gets called. Almost all servers, like gRPC, HTTP servers would be in this case. Sample code: func(ctx context.Context) error { // Prepare resources and return error if applicable. // Use defer to clean up resources (if any).
// Create server instance which has a dedicated closer. srv := NewServer()
return run.WithCloser(srv.Start, srv.Stop)() }
Since all functions are synchronous, the idiomatic defer works well for resource cleanup. It also improves code readability and cohesion.
It would not assume strict order on running these functions since every one runs on its own goroutine. If a function depends on other functions, it needs external check like periodically ping or channel notification.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Parallel ¶ added in v0.2.0
Parallel runs runners synchronously.
It blocks until all runners have returned, then returns the first non-nil error (if any) from them.
Example ¶
ExampleParallel demos block and unblock functions are running simultaneously.
package main import ( "context" "fmt" "os/signal" "syscall" "time" "github.com/ktong/nilgo/run" ) func main() { ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM) _ = run.Parallel( ctx, func(ctx context.Context) error { fmt.Println("Server is running.") defer func() { fmt.Println("Server is stopped.") }() <-ctx.Done() return nil }, func(context.Context) error { time.Sleep(time.Millisecond) fmt.Println("Job has been run.") cancel() return nil }, ) }
Output: Server is running. Job has been run. Server is stopped.
func WithCloser ¶
func WithCloser(runner func(context.Context) error, closer func() error) func(context.Context) error
WithCloser wraps a runner with a dedicated close function, which should cause the runner returns when invoked.
It guarantees both runner and closer complete and returns the first non-nil error if received.
Example ¶
ExampleWithCloser demos a function needs a dedicated closer terminates it.
package main import ( "context" "fmt" "os/signal" "syscall" "time" "github.com/ktong/nilgo/run" ) func main() { ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM) stopChan := make(chan struct{}) _ = run.Parallel( ctx, run.WithCloser( func(context.Context) error { fmt.Println("Server is running.") defer func() { fmt.Println("Server is stopped.") }() <-stopChan return nil }, func() error { fmt.Println("Server is stopping.") close(stopChan) return nil }, ), func(context.Context) error { time.Sleep(time.Millisecond) cancel() return nil }, ) }
Output: Server is running. Server is stopping. Server is stopped.
Types ¶
This section is empty.