├── .gitignore ├── Gopkg.lock ├── Gopkg.toml ├── README.md ├── circuitbreaker └── breaker.go ├── retry └── retry.go ├── slowserver └── slow.go └── timeout ├── leak.go └── timeout.go /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "master" 6 | name = "github.com/afex/hystrix-go" 7 | packages = [ 8 | "hystrix", 9 | "hystrix/metric_collector", 10 | "hystrix/rolling" 11 | ] 12 | revision = "27fae8d30f1a3cbcab6618d2ee55a4cb43064376" 13 | 14 | [[projects]] 15 | branch = "master" 16 | name = "github.com/bcicen/grmon" 17 | packages = ["."] 18 | revision = "c4d4b500d709ad6a7afac094514452fa3e1b41e3" 19 | 20 | [[projects]] 21 | name = "github.com/gojektech/heimdall" 22 | packages = ["."] 23 | revision = "b496d1f3593487abf8161822f38a6612704fdc44" 24 | version = "v3.0.0" 25 | 26 | [[projects]] 27 | name = "github.com/gojektech/valkyrie" 28 | packages = ["."] 29 | revision = "6aee720afcdffc337029305c126e0079491063f0" 30 | version = "v1.0" 31 | 32 | [[projects]] 33 | name = "github.com/pkg/errors" 34 | packages = ["."] 35 | revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 36 | version = "v0.8.0" 37 | 38 | [solve-meta] 39 | analyzer-name = "dep" 40 | analyzer-version = 1 41 | inputs-digest = "2b4a02aa013b0e3fa968792a68deeea1308e012ae918bc4f8892bfc5352aa89d" 42 | solver-name = "gps-cdcl" 43 | solver-version = 1 44 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | branch = "master" 30 | name = "github.com/bcicen/grmon" 31 | 32 | [[constraint]] 33 | name = "github.com/gojektech/heimdall" 34 | version = "3.0.0" 35 | 36 | [prune] 37 | go-tests = true 38 | unused-packages = true 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gophercon-2018 2 | ## Code companion for my talk at Gophercon India 2018, slides [here](http://slides.com/rajeevbharshetty/resiliency-in-distributed-systems) 3 | 4 | ## Usage: 5 | Run `dep ensure` for pulling in dependencies 6 | 7 | ### Timeout 8 | To start a slow server 9 | Run 10 | ``` 11 | go run timeout/leak.go 12 | 13 | ``` 14 | 15 | To start a non-leaking server 16 | Run 17 | ``` 18 | go run timeout/timeout.go 19 | 20 | ``` 21 | 22 | ### Retry 23 | 24 | To start a retry server 25 | Run 26 | ``` 27 | go run retry/retry.go 28 | 29 | ``` 30 | 31 | ### Circuit Breaker 32 | 33 | To start a circuit breaker server 34 | Run 35 | ``` 36 | go run circuitbreaker/breaker.go 37 | 38 | ``` 39 | -------------------------------------------------------------------------------- /circuitbreaker/breaker.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "time" 7 | 8 | _ "github.com/bcicen/grmon" 9 | "github.com/gojektech/heimdall" 10 | ) 11 | 12 | func main() { 13 | http.HandleFunc("/hello", http.HandlerFunc(hello)) 14 | log.Print("Started server on port :8004") 15 | http.ListenAndServe(":8004", nil) 16 | } 17 | 18 | func hello(w http.ResponseWriter, r *http.Request) { 19 | log.Print("Making request to slow server on port:", 9999) 20 | 21 | fallbackFn := func(err error) error { 22 | // Handle failure 23 | return err 24 | } 25 | 26 | timeoutInMillis := 10 27 | timeout := 10 * time.Millisecond 28 | 29 | hystrixConfig := heimdall.NewHystrixConfig("MyCommand", heimdall.HystrixCommandConfig{ 30 | Timeout: timeoutInMillis, 31 | MaxConcurrentRequests: 100, 32 | ErrorPercentThreshold: 25, 33 | SleepWindow: 10, 34 | RequestVolumeThreshold: 10, 35 | FallbackFunc: fallbackFn, 36 | }) 37 | 38 | httpClient := heimdall.NewHystrixHTTPClient(timeout, hystrixConfig) 39 | 40 | _, err := httpClient.Get("http://localhost:9999/drivers", http.Header{}) 41 | if err != nil { 42 | log.Print("failed with error: %s", err) 43 | w.WriteHeader(http.StatusInternalServerError) 44 | return 45 | } 46 | 47 | w.Write([]byte("Hello Gophercon")) 48 | } 49 | -------------------------------------------------------------------------------- /retry/retry.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "time" 7 | 8 | _ "github.com/bcicen/grmon" 9 | "github.com/gojektech/heimdall" 10 | ) 11 | 12 | func main() { 13 | http.HandleFunc("/hello", http.HandlerFunc(hello)) 14 | log.Print("Started server on port :8003") 15 | http.ListenAndServe(":8003", nil) 16 | } 17 | 18 | func hello(w http.ResponseWriter, r *http.Request) { 19 | log.Print("Making request to slow server on port:", 9999) 20 | 21 | backoffInterval := 500 * time.Millisecond 22 | maximumJitterInterval := 50 * time.Millisecond 23 | 24 | backoff := heimdall.NewConstantBackoff(backoffInterval, maximumJitterInterval) 25 | retrier := heimdall.NewRetrier(backoff) 26 | httpClient := heimdall.NewHTTPClient(1 * time.Millisecond) 27 | 28 | httpClient.SetRetrier(retrier) 29 | httpClient.SetRetryCount(3) 30 | 31 | _, err := httpClient.Get("http://localhost:9999/drivers", http.Header{}) 32 | if err != nil { 33 | log.Print("failed with error: %s", err) 34 | w.WriteHeader(http.StatusInternalServerError) 35 | return 36 | } 37 | 38 | w.Write([]byte("Hello Gophercon")) 39 | } 40 | -------------------------------------------------------------------------------- /slowserver/slow.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/drivers", http.HandlerFunc(drivers)) 11 | log.Print("Started slow server on port :9999") 12 | http.ListenAndServe(":9999", nil) 13 | } 14 | 15 | func drivers(w http.ResponseWriter, r *http.Request) { 16 | time.Sleep(100 * time.Second) 17 | } 18 | -------------------------------------------------------------------------------- /timeout/leak.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | _ "github.com/bcicen/grmon" 8 | ) 9 | 10 | func main() { 11 | http.HandleFunc("/hello", http.HandlerFunc(hello)) 12 | 13 | log.Print("Started server on port :8000") 14 | http.ListenAndServe(":8000", nil) 15 | } 16 | 17 | func hello(w http.ResponseWriter, r *http.Request) { 18 | log.Print("Making request to slow server on port:", 9999) 19 | 20 | httpClient := http.Client{} 21 | _, err := httpClient.Get("http://localhost:9999/drivers") 22 | if err != nil { 23 | log.Print("failed with error: %s", err) 24 | return 25 | } 26 | 27 | w.Write([]byte("Hello Gophercon 2018")) 28 | } 29 | -------------------------------------------------------------------------------- /timeout/timeout.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "time" 7 | 8 | _ "github.com/bcicen/grmon" 9 | "github.com/gojektech/heimdall" 10 | ) 11 | 12 | func main() { 13 | http.HandleFunc("/hello", http.HandlerFunc(hello)) 14 | log.Print("Started server on port :8001") 15 | http.ListenAndServe(":8001", nil) 16 | } 17 | 18 | func hello(w http.ResponseWriter, r *http.Request) { 19 | log.Print("Making request to slow server on port:", 9999) 20 | 21 | httpClient := heimdall.NewHTTPClient(1 * time.Millisecond) 22 | _, err := httpClient.Get("http://localhost:9999/drivers", http.Header{}) 23 | if err != nil { 24 | log.Print("failed with error: %s", err) 25 | return 26 | } 27 | 28 | w.Write([]byte("Hello Gophercon")) 29 | } 30 | --------------------------------------------------------------------------------