goresilience: github.com/slok/goresilience Index | Examples | Files | Directories

package goresilience

import "github.com/slok/goresilience"

Package goresilience is a framework/lirbary of utilities to improve the resilience of programs easily.

The library is based on `goresilience.Runner` interface, this runners can be chained using the decorator pattern (like std library `http.Handler` interface). This makes the library being extensible, flexible and clean to use. The runners can be chained like if they were middlewares that could act on all the execution process of the `goresilience.Func`.

Will use a single runner, the retry with the default settings this will make the `gorunner.Func` to be executed and retried N times if it fails.

Code:

// Create our func `runner`. Use nil as it will not be chained with another `Runner`.
cmd := retry.New(retry.Config{})

// Execute.
var result string
err := cmd.Run(context.TODO(), func(ctx context.Context) error {
    resp, err := http.Get("https://bruce.wayne.is.batman.io")
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    result = string(b)
    return nil
})

// We could fallback to get a Hystrix like behaviour.
if err != nil {
    result = "fallback result"
}

fmt.Printf("result is: %s\n", result)

Will use more than one `goresilience.Runner` and chain them to create a very resilient execution of the `goresilience.Func`. In this case we will create a runner that retries and also times out. And we will configure the timeout.

Code:

// Create our chain, first the retry and then the timeout with 100ms.
cmd := goresilience.RunnerChain(
    retry.NewMiddleware(retry.Config{}),
    timeout.NewMiddleware(timeout.Config{
        Timeout: 100 * time.Millisecond,
    }),
)

var result string
err := cmd.Run(context.TODO(), func(ctx context.Context) error {
    resp, err := http.Get("https://bruce.wayne.is.batman.io")
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    b, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }

    result = string(b)
    return nil
})

// We could fallback to get a Hystrix like behaviour.
if err != nil {
    result = "fallback result"
}

fmt.Printf("result is: %s\n", result)

Will measure all the execution through the runners uwing prometheus metrics.

Code:

// Create a prometheus registry and expose that registry over http.
promreg := prometheus.NewRegistry()
go func() {
    http.ListenAndServe(":8081", promhttp.HandlerFor(promreg, promhttp.HandlerOpts{}))
}()

// Create the metrics recorder for our runner.
metricsRecorder := metrics.NewPrometheusRecorder(promreg)

// Create our chain with our metircs wrapper.
cmd := goresilience.RunnerChain(
    metrics.NewMiddleware("example-metrics", metricsRecorder),
    retry.NewMiddleware(retry.Config{}),
    timeout.NewMiddleware(timeout.Config{
        Timeout: 100 * time.Millisecond,
    }),
)

var result string
err := cmd.Run(context.TODO(), func(ctx context.Context) error {
    sec := time.Now().Second()
    if sec%2 == 0 {
        return fmt.Errorf("error because %d is even", sec)
    }
    return nil
})

// We could fallback to get a Hystrix like behaviour.
if err != nil {
    result = "fallback result"
}

fmt.Printf("result is: %s\n", result)

Is an example to show that when the result is not needed we don't need to use and inline function.

Code:

cmd := retry.New(retry.Config{})

// Execute.
err := cmd.Run(context.TODO(), myFunc)
if err != nil {
    // Do fallback.
}

Is an example to show that we could use objects aslo to pass parameter and get our results.

Code:

type myfuncResult struct {
    name     string
    lastName string
    result   string
}

cmd := retry.New(retry.Config{})

// Execute.
res := myfuncResult{
    name:     "Bruce",
    lastName: "Wayne",
}
err := cmd.Run(context.TODO(), func(ctx context.Context) error {
    if res.name == "Bruce" && res.lastName == "Wayne" {
        res.result = "Batman"
    }
    return errors.New("identity unknown")
})

if err != nil {
    res.result = "Unknown"
}

fmt.Printf("%s %s is %s", res.name, res.lastName, res.result)

Index

Examples

Package Files

goresilience.go

type Func Uses

type Func func(ctx context.Context) error

Func is the function to execute with resilience.

type Middleware Uses

type Middleware func(Runner) Runner

Middleware represents a middleware for a runner, it takes a runner and returns a runner.

type Runner Uses

type Runner interface {
    // Run will run the unit of execution passed on f.
    Run(ctx context.Context, f Func) error
}

Runner knows how to execute a execution logic and returns error if errors.

func RunnerChain Uses

func RunnerChain(middlewares ...Middleware) Runner

RunnerChain will get N middleares and will create a Runner chain with them in the order that have been passed.

func SanitizeRunner Uses

func SanitizeRunner(r Runner) Runner

SanitizeRunner returns a safe execution Runner if the runner is nil. Usually this helper will be used for the last part of the runner chain when the runner is nil, so instead of acting on a nil Runner its executed on a `command` Runner, this runner knows how to execute the `Func` function. It's safe to use it always as if it encounters a safe Runner it will return that Runner.

type RunnerFunc Uses

type RunnerFunc func(ctx context.Context, f Func) error

RunnerFunc is a helper that will satisfies circuit.Breaker interface by using a function.

func (RunnerFunc) Run Uses

func (r RunnerFunc) Run(ctx context.Context, f Func) error

Run satisfies Runner interface.

Directories

PathSynopsis
bulkhead
chaos
circuitbreaker
concurrencylimit
concurrencylimit/execute
concurrencylimit/limit
errors
internal/mocksPackage mocks will have all the mocks of the library, we'll try to use mocking using blackbox testing and integration tests whenever is possible.
internal/mocks/concurrencylimit/execute
internal/mocks/concurrencylimit/limit
metrics
retry
timeout

Package goresilience imports 2 packages (graph) and is imported by 8 packages. Updated 2019-05-17. Refresh now. Tools for package owners.