From 5553e59b5c3e728667812755d0e91e67c11a0f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Setni=C4=8Dka?= Date: Mon, 19 Oct 2026 12:34:44 +0200 Subject: [PATCH] bugfix: balancer keepalive connections were never reused with proxy_bind. When proxy_bind sets the local address and balancer_by_lua* enables keepalive without calling balancer.bind_to_local_addr(), pc->local holds the proxy_bind address while bp->local is NULL. free_peer hashed the saved connection with bp->local, but get_cached_item looks it up with pc->local, so the lookup never matched: every connection was saved, never reused, and closed when it idled out. Hash with pc->local, which is the address the connection was bound to and the one stored in item->local_sockaddr. Since nginx 1.29.7 the "keepalive" directive is enabled by default and its cache takes the connections before the Lua pool, so the test turns it off with "keepalive 0" on those versions. --- src/ngx_http_lua_balancer.c | 2 +- t/188-balancer_keepalive_pool_max_retry.t | 44 ++++++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/ngx_http_lua_balancer.c b/src/ngx_http_lua_balancer.c index bc52af16a3..bd56d9da19 100644 --- a/src/ngx_http_lua_balancer.c +++ b/src/ngx_http_lua_balancer.c @@ -660,7 +660,7 @@ ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data, ngx_queue_insert_head(&lscf->balancer.cache, q); hash = ngx_http_lua_balancer_calc_hash(host, bp->sockaddr, bp->socklen, - bp->local); + pc->local); item->hash = hash; hash %= lscf->balancer.bucket_cnt; ngx_queue_insert_head(&lscf->balancer.buckets[hash], &item->hnode); diff --git a/t/188-balancer_keepalive_pool_max_retry.t b/t/188-balancer_keepalive_pool_max_retry.t index 6588312ab5..e83e8e048f 100644 --- a/t/188-balancer_keepalive_pool_max_retry.t +++ b/t/188-balancer_keepalive_pool_max_retry.t @@ -6,7 +6,7 @@ use Cwd qw(cwd); log_level('info'); repeat_each(1); -plan tests => repeat_each() * (blocks() * 6 - 1); +plan tests => repeat_each() * (blocks() * 6 + 5); my $pwd = cwd(); @@ -214,3 +214,45 @@ qr/\A\Q$first\E(?:\Q$extra\E)?\z/ --- no_error_log retry storm guard [alert] + + + +=== TEST 3: reuse keepalive connections per proxy_bind address +proxy_bind sets the local address of the upstream connection, while +balancer.bind_to_local_addr() is not called. +--- http_config eval +# Since nginx version 1.29.7, the "keepalive" directive is enabled by +# default and its cache takes the connections before the Lua pool sees them. +my $keepalive = $Test::Nginx::Util::NginxVersion >= 1.029007 ? + "keepalive 0;" : ""; + +qq{ + upstream backend { + server 0.0.0.1; + $keepalive + balancer_by_lua_block { + local b = require "ngx.balancer" + assert(b.set_current_peer("127.0.0.1", \$TEST_NGINX_RAND_PORT_1)) + assert(b.enable_keepalive()) + } + } + + server { + listen 127.0.0.1:\$TEST_NGINX_RAND_PORT_1; + return 200 "\$remote_addr \$connection_requests"; + } +} +--- config + location = /t { + proxy_bind $arg_bind; + proxy_pass http://backend; + proxy_http_version 1.1; + proxy_set_header Connection ""; + } +--- request eval +["GET /t?bind=127.0.0.1", "GET /t?bind=127.0.0.2", + "GET /t?bind=127.0.0.1", "GET /t?bind=127.0.0.2"] +--- response_body eval +["127.0.0.1 1", "127.0.0.2 1", "127.0.0.1 2", "127.0.0.2 2"] +--- no_error_log +[error]