From 2c580ed67e4e39a8e377fc69596b7152c08453cc Mon Sep 17 00:00:00 2001 From: dovtang Date: Wed, 25 Mar 2026 14:35:57 +0800 Subject: [PATCH] fix: prevent service degradation on config reload failure When applyConfig() fails during hot reload, the old proxy was being destroyed before the new proxy was successfully initialized, causing partial service outage. Changes: - main.go: Use temporary variable to create and validate new proxy before replacing the global instance. On failure, cleanup new proxy and keep old proxy running. - proxy.go: Fix bug where maxIdleConns was incorrectly assigned MaxIdleConnsPerHost --- main.go | 24 +++++++++++++++++++----- proxy.go | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 84f594dd..2d6d9bf2 100644 --- a/main.go +++ b/main.go @@ -299,12 +299,26 @@ func proxyConfigChanged(cfgCp *config.ConnectionPool, rp *reverseProxy) bool { } func applyConfig(cfg *config.Config) error { - if proxy == nil || proxyConfigChanged(&cfg.ConnectionPool, proxy) { - proxy = newReverseProxy(&cfg.ConnectionPool) - } - if err := proxy.applyConfig(cfg); err != nil { - return err + needNewProxy := proxy == nil || proxyConfigChanged(&cfg.ConnectionPool, proxy) + + if needNewProxy { + newProxy := newReverseProxy(&cfg.ConnectionPool) + if err := newProxy.applyConfig(cfg); err != nil { + close(newProxy.reloadSignal) + newProxy.reloadWG.Wait() + return err + } + if proxy != nil { + close(proxy.reloadSignal) + proxy.reloadWG.Wait() + } + proxy = newProxy + } else { + if err := proxy.applyConfig(cfg); err != nil { + return err + } } + allowedNetworksHTTP.Store(&cfg.Server.HTTP.AllowedNetworks) allowedNetworksHTTPS.Store(&cfg.Server.HTTPS.AllowedNetworks) allowedNetworksMetrics.Store(&cfg.Server.Metrics.AllowedNetworks) diff --git a/proxy.go b/proxy.go index 72ec90bb..574dcb24 100644 --- a/proxy.go +++ b/proxy.go @@ -78,7 +78,7 @@ func newReverseProxy(cfgCp *config.ConnectionPool) *reverseProxy { }, reloadSignal: make(chan struct{}), reloadWG: sync.WaitGroup{}, - maxIdleConns: cfgCp.MaxIdleConnsPerHost, + maxIdleConns: cfgCp.MaxIdleConns, maxIdleConnsPerHost: cfgCp.MaxIdleConnsPerHost, } }