rutina
Package Rutina (russian "рутина" - ordinary boring everyday work) is routine orchestrator for your application.
It seems like https://godoc.org/golang.org/x/sync/errgroup with some different:
1) propagates context to every routines. So routine can check if context stopped (ctx.Done()
).
2) by default cancels context when any routine ends with any result (not only when error result). Can be configured by option OptionCancelByError
.
3) already has optional signal handler ListenOsSignals()
When it need?
Usually, when your program consists of several routines (i.e.: http server, metrics server and os signals subscriber) and you want to stop all routines when one of them ends (i.e.: by TERM os signal in signal subscriber).
Usage
New instance
r := rutina.New()
or with options (see below):
r := rutina.New(...Option)
or r.WithOptions(...Option)
Start new routine
r.Go(func (ctx context.Context) error {
...do something...
})
Wait routines to complete
err := r.Wait()
Here err = first error in any routine
Options
Usage options
r := rutina.New(option1, option2, ...)
or
r := rutina.New()
r = r.WithOptions(option1, option2, ...) // Returns new instance of Rutina!
Logger
rutina.WithLogger(logger log.Logger) Option
or rutina.WithStdLogger() Option
Custom context
rutina.WithContext(ctx context.Context) Option
Cancel only by errors
rutina.WithCancelByError() Option
If this option set, rutina doesnt cancel context if routine completed without error.
Example
HTTP server with graceful shutdown (example/http_server.go
):
// New instance with builtin context. Alternative: r, ctx := rutina.WithContext(ctx)
r, _ := rutina.New(rutina.WithStdLogger())
srv := &http.Server{Addr: ":8080"}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "hello world\n")
})
// Starting http server and listen connections
r.Go(func(ctx context.Context) error {
if err := srv.ListenAndServe(); err != nil {
return err
}
log.Println("Server stopped")
return nil
})
// Gracefully stoping server when context canceled
r.Go(func(ctx context.Context) error {
<-ctx.Done()
log.Println("Stopping server...")
return srv.Shutdown(ctx)
})
// OS signals listener
r.ListenOsSignals()
if err := r.Wait(); err != nil {
log.Fatal(err)
}
log.Println("All routines successfully stopped")