Documentation ¶
Overview ¶
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`.
Example (Basic) ¶
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.
package main import ( "context" "fmt" "io/ioutil" "net/http" "github.com/slok/goresilience/retry" ) func main() { // 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) }
Output:
Example (Chain) ¶
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.
package main import ( "context" "fmt" "io/ioutil" "net/http" "time" "github.com/slok/goresilience" "github.com/slok/goresilience/retry" "github.com/slok/goresilience/timeout" ) func main() { // 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) }
Output:
Example (Metrics) ¶
Will measure all the execution through the runners uwing prometheus metrics.
package main import ( "context" "fmt" "net/http" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/slok/goresilience" "github.com/slok/goresilience/metrics" "github.com/slok/goresilience/retry" "github.com/slok/goresilience/timeout" ) func main() { // 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) }
Output:
Example (Noresult) ¶
Is an example to show that when the result is not needed we don't need to use and inline function.
package main import ( "context" "github.com/slok/goresilience/retry" ) func myFunc(ctx context.Context) error { return nil } func main() { cmd := retry.New(retry.Config{}) // Execute. err := cmd.Run(context.TODO(), myFunc) if err != nil { // Do fallback. } }
Output:
Example (Structresult) ¶
Is an example to show that we could use objects aslo to pass parameter and get our results.
package main import ( "context" "errors" "fmt" "github.com/slok/goresilience/retry" ) func main() { 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) }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Middleware ¶
Middleware represents a middleware for a runner, it takes a runner and returns a runner.
type Runner ¶
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 ¶
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 ¶
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.
Directories ¶
Path | Synopsis |
---|---|
examples
|
|
internal
|
|
mocks
Package mocks will have all the mocks of the library, we'll try to use mocking using blackbox testing and integration tests whenever is possible.
|
Package mocks will have all the mocks of the library, we'll try to use mocking using blackbox testing and integration tests whenever is possible. |