Skip to content

Instantly share code, notes, and snippets.

@SirPhemmiey
Created May 25, 2024 16:02
Show Gist options
  • Save SirPhemmiey/b9ed2d744d8ee3b4897b100f35b7de72 to your computer and use it in GitHub Desktop.
Save SirPhemmiey/b9ed2d744d8ee3b4897b100f35b7de72 to your computer and use it in GitHub Desktop.
Implementing a circuit breaker pattern (with prometheus) in go
package main
import (
"fmt"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sony/gobreaker"
)
var (
requestCount = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "request_count",
Help: "Number of requests.",
},
[]string{"state"},
)
)
func init() {
prometheus.MustRegister(requestCount)
}
func callExternalAPI() (int, error) {
resp, err := http.Get("https://example.com/api")
if err != nil {
return 0, err
}
defer resp.Body.Close()
return resp.StatusCode, nil
}
func main() {
http.Handle("/metrics", promhttp.Handler())
settings := gobreaker.Settings{
Name: "API Circuit Breaker",
MaxRequests: 5,
Interval: 60 * time.Second,
Timeout: 30 * time.Second,
ReadyToTrip: func(counts gobreaker.Counts) bool {
requestCount.WithLabelValues("failure").Inc()
return counts.ConsecutiveFailures > 3
},
OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) {
fmt.Printf("Circuit Breaker %s changed from %s to %s\n", name, from, to)
requestCount.WithLabelValues(to.String()).Inc()
},
}
cb := gobreaker.NewCircuitBreaker(settings)
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
_, err := cb.Execute(func() (interface{}, error) {
return callExternalAPI()
})
if err != nil {
http.Error(w, "Service Unavailable", http.StatusServiceUnavailable)
return
}
w.Write([]byte("Request succeeded"))
})
fmt.Println("Starting server on :8111...")
if err := http.ListenAndServe(":8111", nil); err != nil {
fmt.Printf("Server failed to start: %v\n", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment