github.com/blend/go-sdk@v1.20220411.3/examples/breaker/main.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package main 9 10 import ( 11 "context" 12 "encoding/json" 13 "flag" 14 "fmt" 15 "math/rand" 16 "net/http" 17 "net/http/httptest" 18 "time" 19 20 "github.com/blend/go-sdk/breaker" 21 "github.com/blend/go-sdk/ex" 22 "github.com/blend/go-sdk/r2" 23 "github.com/blend/go-sdk/webutil" 24 ) 25 26 // Result is a json thingy. 27 type Result struct { 28 ID int `json:"id"` 29 Name string `json:"name"` 30 } 31 32 func createUpstreamCaller(opts ...r2.Option) breaker.Actioner { 33 return breaker.ActionerFunc(func(ctx context.Context, args interface{}) (interface{}, error) { 34 res, err := r2.New(args.(string), opts...).Do() 35 if err != nil { 36 return nil, err 37 } 38 defer res.Body.Close() 39 if res.StatusCode >= 300 { 40 return nil, fmt.Errorf("non 200 status code returned from remote") 41 } 42 var result Result 43 json.NewDecoder(res.Body).Decode(&result) 44 return result, nil 45 }) 46 } 47 48 var ( 49 flagNumCalls = flag.Int("num-calls", 1024, "The number of calls") 50 ) 51 52 func init() { 53 flag.Parse() 54 } 55 56 func main() { 57 mockServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { 58 if rand.Float64() > 0.5 { 59 http.Error(rw, "should fail", http.StatusInternalServerError) 60 return 61 } 62 webutil.WriteJSON(rw, http.StatusOK, Result{1, "Foo"}) 63 })) 64 defer mockServer.Close() 65 66 b := breaker.New( 67 breaker.OptOpenExpiryInterval(5 * time.Second), 68 ) 69 cb := b.Intercept(createUpstreamCaller()) 70 71 var err error 72 var res interface{} 73 for x := 0; x < *flagNumCalls; x++ { 74 if res, err = cb.Action(context.Background(), mockServer.URL); err != nil { 75 fmt.Printf("(%v) circuit breaker error: %v\n", b.EvaluateState(context.Background()), err) 76 if ex.Is(err, breaker.ErrOpenState) { 77 time.Sleep(5 * time.Second) 78 } else { 79 time.Sleep(100 * time.Millisecond) 80 } 81 } else { 82 fmt.Printf("(%v) result: %v\n", b.EvaluateState(context.Background()), res) 83 time.Sleep(100 * time.Millisecond) 84 } 85 } 86 }