From 12513943cc3c213579de87643fca12d0dcef88e7 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Sat, 25 Apr 2026 06:04:15 +0300 Subject: [PATCH] feat: Add circuit breaker protection to Kubernetes service with configurable thresholds and timeout - Add circuitbreaker import to kubernetes.go - Add circuitBreaker field to KubernetesService struct - Add circuit breaker initialization in NewKubernetesService with Config struct - Add K8S_CB_FAILURE_THRESHOLD environment variable with 5 default - Add K8S_CB_SUCCESS_THRESHOLD environment variable with 2 default - Add K8S_CB_TIMEOUT_SECONDS environment variable with 60 second default - Add getEnvUint helper --- .../internal/services/kubernetes.go | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/apps/api-server/internal/services/kubernetes.go b/apps/api-server/internal/services/kubernetes.go index 3030931..f1a354f 100644 --- a/apps/api-server/internal/services/kubernetes.go +++ b/apps/api-server/internal/services/kubernetes.go @@ -14,12 +14,15 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/homedir" + + "github.com/nutcas3/telecom-platform/apps/api-server/internal/circuitbreaker" ) // KubernetesService provides real Kubernetes cluster operations using client-go type KubernetesService struct { - clientset *kubernetes.Clientset - namespace string + clientset *kubernetes.Clientset + namespace string + circuitBreaker *circuitbreaker.CircuitBreaker } // NewKubernetesService creates a Kubernetes client using in-cluster config or kubeconfig @@ -51,12 +54,34 @@ func NewKubernetesService() (*KubernetesService, error) { } } + // Initialize circuit breaker for Kubernetes API calls + cbConfig := circuitbreaker.Config{ + FailureThreshold: getEnvUint("K8S_CB_FAILURE_THRESHOLD", 5), + SuccessThreshold: getEnvUint("K8S_CB_SUCCESS_THRESHOLD", 2), + Timeout: time.Duration(getEnvUint("K8S_CB_TIMEOUT_SECONDS", 60)) * time.Second, + } + circuitBreaker := circuitbreaker.NewCircuitBreaker(cbConfig) + return &KubernetesService{ - clientset: clientset, - namespace: namespace, + clientset: clientset, + namespace: namespace, + circuitBreaker: circuitBreaker, }, nil } +func getEnvUint(key string, defaultVal uint) uint { + val := os.Getenv(key) + if val == "" { + return defaultVal + } + var result uint + _, err := fmt.Sscanf(val, "%d", &result) + if err != nil { + return defaultVal + } + return result +} + // getInClusterNamespace reads the namespace from the in-cluster service account func getInClusterNamespace() (string, error) { data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")