@@ -68,6 +68,11 @@ type ProxyServerOnline struct {
6868 // BackendClusters represents multiple backend clusters that the proxy can route to. It can be reloaded
6969 // online.
7070 BackendClusters []BackendCluster `yaml:"backend-clusters,omitempty" toml:"backend-clusters,omitempty" json:"backend-clusters,omitempty" reloadable:"true"`
71+ // FailBackendList contains backend pod names or backend addresses (IP:port) that should be drained immediately
72+ // and excluded from new routing.
73+ FailBackendList []string `yaml:"fail-backend-list,omitempty" toml:"fail-backend-list,omitempty" json:"fail-backend-list,omitempty" reloadable:"true"`
74+ // FailoverTimeout is the grace period in seconds before force closing the remaining connections on failed backends.
75+ FailoverTimeout int `yaml:"failover-timeout,omitempty" toml:"failover-timeout,omitempty" json:"failover-timeout,omitempty" reloadable:"true"`
7176}
7277
7378type ProxyServer struct {
@@ -134,6 +139,7 @@ func NewConfig() *Config {
134139 cfg .Proxy .FrontendKeepalive , cfg .Proxy .BackendHealthyKeepalive , cfg .Proxy .BackendUnhealthyKeepalive = DefaultKeepAlive ()
135140 cfg .Proxy .PDAddrs = "127.0.0.1:2379"
136141 cfg .Proxy .GracefulCloseConnTimeout = 15
142+ cfg .Proxy .FailoverTimeout = 60
137143
138144 cfg .API .Addr = "0.0.0.0:3080"
139145
@@ -160,6 +166,7 @@ func (cfg *Config) Clone() *Config {
160166 newCfg .Labels = maps .Clone (cfg .Labels )
161167 newCfg .Proxy .PublicEndpoints = slices .Clone (cfg .Proxy .PublicEndpoints )
162168 newCfg .Proxy .BackendClusters = slices .Clone (cfg .Proxy .BackendClusters )
169+ newCfg .Proxy .FailBackendList = slices .Clone (cfg .Proxy .FailBackendList )
163170 for i := range newCfg .Proxy .BackendClusters {
164171 newCfg .Proxy .BackendClusters [i ].NSServers = slices .Clone (newCfg .Proxy .BackendClusters [i ].NSServers )
165172 }
@@ -279,6 +286,23 @@ func (ps *ProxyServer) Check() error {
279286 return errors .Wrapf (ErrInvalidConfigValue , "invalid proxy.backend-clusters.ns-servers: %s" , err .Error ())
280287 }
281288 }
289+ if ps .FailoverTimeout < 0 {
290+ return errors .Wrapf (ErrInvalidConfigValue , "proxy.failover-timeout must be greater than or equal to 0" )
291+ }
292+ failBackends := ps .FailBackendList [:0 ]
293+ failBackendSet := make (map [string ]struct {}, len (ps .FailBackendList ))
294+ for i , backendName := range ps .FailBackendList {
295+ backendName = strings .TrimSpace (backendName )
296+ if backendName == "" {
297+ return errors .Wrapf (ErrInvalidConfigValue , "proxy.fail-backend-list[%d] is empty" , i )
298+ }
299+ if _ , ok := failBackendSet [backendName ]; ok {
300+ return errors .Wrapf (ErrInvalidConfigValue , "duplicate proxy.fail-backend-list entry %s" , backendName )
301+ }
302+ failBackendSet [backendName ] = struct {}{}
303+ failBackends = append (failBackends , backendName )
304+ }
305+ ps .FailBackendList = failBackends
282306 return nil
283307}
284308
0 commit comments