rutina/README.md
2019-01-17 07:57:51 +03:00

2.4 KiB
Executable file

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")