From e47a098d41acda52aad31bd6ae0140e59ad3746b Mon Sep 17 00:00:00 2001 From: Jared Patterson Date: Sun, 15 Mar 2026 06:41:57 +1300 Subject: [PATCH] Idle Connection Timeout Configuration - Adds configuration for connection pool idle connetion timeouts - Decreases the default idle connection timeout to be < the Clickhouse keep-alive default (10s) Fixes: #92 --- config/README.md | 2 ++ config/config.go | 5 +++++ config/config_test.go | 2 ++ config/testdata/full.yml | 4 ++++ proxy.go | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/config/README.md b/config/README.md index 45abf23f..a97812ae 100644 --- a/config/README.md +++ b/config/README.md @@ -40,6 +40,8 @@ max_error_reason_size: connection_pool: max_idle_conns: 100 max_idle_conns_per_host: 2 + # Connection idle timeout must be < Clickhouse `keep_alive_timeout`. + idle_conn_timeout: 9 server: [optional] diff --git a/config/config.go b/config/config.go index a8f94c4e..c7aa4ac3 100644 --- a/config/config.go +++ b/config/config.go @@ -42,6 +42,7 @@ var ( defaultConnectionPool = ConnectionPool{ MaxIdleConns: 100, MaxIdleConnsPerHost: 2, + IdleConnTimeout: Duration(9 * time.Second), } defaultExecutionTime = Duration(120 * time.Second) @@ -1062,6 +1063,10 @@ type ConnectionPool struct { // Maximum number of idle connections between chproxy and particuler ClickHouse instance MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host,omitempty"` + // Time that an idle connection is kept in the pool before being discarded. + // Should be set below the ClickHouse server's keep_alive_timeout. + IdleConnTimeout Duration `yaml:"idle_conn_timeout,omitempty"` + // Catches all undefined fields XXX map[string]interface{} `yaml:",inline"` } diff --git a/config/config_test.go b/config/config_test.go index 76c1e233..320ebdfb 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -219,6 +219,7 @@ var fullConfig = Config{ ConnectionPool: ConnectionPool{ MaxIdleConns: 100, MaxIdleConnsPerHost: 2, + IdleConnTimeout: Duration(9 * time.Second), }, Users: []User{ @@ -946,6 +947,7 @@ param_groups: connection_pool: max_idle_conns: 100 max_idle_conns_per_host: 2 + idle_conn_timeout: 9s `, redisPort) tested := fullConfig.String() if tested != expected { diff --git a/config/testdata/full.yml b/config/testdata/full.yml index 020a5d9f..8c8b4193 100644 --- a/config/testdata/full.yml +++ b/config/testdata/full.yml @@ -111,6 +111,10 @@ connection_pool: # Number of connections per ClickHouse host to keep open # when they are not needed for clients. max_idle_conns_per_host: 2 + # Idle Timeout For Connections To Clickhouse. This value must be < the Clickhouse + # `keep_alive_timeout` to prevent graceful disconnection race-conditions that can + # result in Bad Gateway (unable to reach host errors) + idle_conn_timeout: 9s # Settings for `chproxy` input interfaces. server: diff --git a/proxy.go b/proxy.go index 72ec90bb..0eaa0ccf 100644 --- a/proxy.go +++ b/proxy.go @@ -62,7 +62,7 @@ func newReverseProxy(cfgCp *config.ConnectionPool) *reverseProxy { ForceAttemptHTTP2: true, MaxIdleConns: cfgCp.MaxIdleConns, MaxIdleConnsPerHost: cfgCp.MaxIdleConnsPerHost, - IdleConnTimeout: 90 * time.Second, + IdleConnTimeout: time.Duration(cfgCp.IdleConnTimeout), TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, }