# HG changeset patch # User Artem Pogartsev <i...@arteomp.com> # Date 1699416491 -10800 # Wed Nov 08 07:08:11 2023 +0300 # Node ID eb0dd3d903431f4dd7a62d629db457ecddeadd96 # Parent 7ec761f0365f418511e30b82e9adf80bc56681df Introduced worker_shutdown_idle_delay.
The directive configures a delay before closing idle connections to be used when gracefully shutting down worker processes. When the timer expires, nginx will attempt to close any remaining idle connections. The delay is only added for connections with the "shutdown_delay" flag, and currently it's only keepalive HTTP/1.1 connections. The behavior is not changed for protocols that have built-in graceful shutdown mechanisms, such as GOAWAY frames in HTTP2 and HTTP3. Although it's perfectly fine to close an HTTP/1.1 connection at any time according to RFC 9112, it may still be useful to delay closing a connection, wait for the next client request, and close the connection with a "Connection: close" header to avoid unnecessary retries by clients. This is especially important for environments with frequent nginx reloads and large amounts of non-idempotent requests which are quite problematic for automatic retries. Should be used carefully to not delay configuration reloads too much (and thus increase nginx resource usage), and ideally in combination with properly configured clients: client_idle_timeout < min(server_shutdown_delay, server_idle_timeout) diff -r 7ec761f0365f -r eb0dd3d90343 contrib/vim/syntax/nginx.vim --- a/contrib/vim/syntax/nginx.vim Thu Oct 26 23:35:09 2023 +0300 +++ b/contrib/vim/syntax/nginx.vim Wed Nov 08 07:08:11 2023 +0300 @@ -705,6 +705,7 @@ syn keyword ngxDirective contained worker_rlimit_core syn keyword ngxDirective contained worker_rlimit_nofile syn keyword ngxDirective contained worker_shutdown_timeout +syn keyword ngxDirective contained worker_shutdown_idle_delay syn keyword ngxDirective contained working_directory syn keyword ngxDirective contained xclient syn keyword ngxDirective contained xml_entities diff -r 7ec761f0365f -r eb0dd3d90343 src/core/nginx.c --- a/src/core/nginx.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/core/nginx.c Wed Nov 08 07:08:11 2023 +0300 @@ -132,6 +132,13 @@ offsetof(ngx_core_conf_t, shutdown_timeout), NULL }, + { ngx_string("worker_shutdown_idle_delay"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + 0, + offsetof(ngx_core_conf_t, shutdown_idle_delay), + NULL }, + { ngx_string("working_directory"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -1115,6 +1122,7 @@ ccf->master = NGX_CONF_UNSET; ccf->timer_resolution = NGX_CONF_UNSET_MSEC; ccf->shutdown_timeout = NGX_CONF_UNSET_MSEC; + ccf->shutdown_idle_delay = NGX_CONF_UNSET_MSEC; ccf->worker_processes = NGX_CONF_UNSET; ccf->debug_points = NGX_CONF_UNSET; @@ -1144,6 +1152,7 @@ ngx_conf_init_value(ccf->master, 1); ngx_conf_init_msec_value(ccf->timer_resolution, 0); ngx_conf_init_msec_value(ccf->shutdown_timeout, 0); + ngx_conf_init_msec_value(ccf->shutdown_idle_delay, 0); ngx_conf_init_value(ccf->worker_processes, 1); ngx_conf_init_value(ccf->debug_points, 0); diff -r 7ec761f0365f -r eb0dd3d90343 src/core/ngx_connection.c --- a/src/core/ngx_connection.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/core/ngx_connection.c Wed Nov 08 07:08:11 2023 +0300 @@ -1427,7 +1427,7 @@ void -ngx_close_idle_connections(ngx_cycle_t *cycle) +ngx_close_idle_connections(ngx_cycle_t *cycle, ngx_msec_t shutdown_delay) { ngx_uint_t i; ngx_connection_t *c; @@ -1439,10 +1439,15 @@ /* THREAD: lock */ if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) { + if (shutdown_delay && c[i].shutdown_delay) { + continue; + } c[i].close = 1; c[i].read->handler(c[i].read); } } + + ngx_set_shutdown_idle_timer(cycle, shutdown_delay); } diff -r 7ec761f0365f -r eb0dd3d90343 src/core/ngx_connection.h --- a/src/core/ngx_connection.h Thu Oct 26 23:35:09 2023 +0300 +++ b/src/core/ngx_connection.h Wed Nov 08 07:08:11 2023 +0300 @@ -183,6 +183,7 @@ unsigned idle:1; unsigned reusable:1; unsigned close:1; + unsigned shutdown_delay:1; unsigned shared:1; unsigned sendfile:1; @@ -222,7 +223,7 @@ void ngx_configure_listening_sockets(ngx_cycle_t *cycle); void ngx_close_listening_sockets(ngx_cycle_t *cycle); void ngx_close_connection(ngx_connection_t *c); -void ngx_close_idle_connections(ngx_cycle_t *cycle); +void ngx_close_idle_connections(ngx_cycle_t *cycle, ngx_msec_t shutdown_delay); ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, ngx_uint_t port); ngx_int_t ngx_tcp_nodelay(ngx_connection_t *c); diff -r 7ec761f0365f -r eb0dd3d90343 src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/core/ngx_cycle.c Wed Nov 08 07:08:11 2023 +0300 @@ -16,6 +16,7 @@ static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log); static void ngx_clean_old_cycles(ngx_event_t *ev); static void ngx_shutdown_timer_handler(ngx_event_t *ev); +static void ngx_shutdown_idle_timer_handler(ngx_event_t *ev); volatile ngx_cycle_t *ngx_cycle; @@ -24,6 +25,7 @@ static ngx_pool_t *ngx_temp_pool; static ngx_event_t ngx_cleaner_event; static ngx_event_t ngx_shutdown_event; +static ngx_event_t ngx_shutdown_idle_event; ngx_uint_t ngx_test_config; ngx_uint_t ngx_dump_config; @@ -1468,3 +1470,30 @@ c[i].read->handler(c[i].read); } } + + +void +ngx_set_shutdown_idle_timer(ngx_cycle_t *cycle, ngx_msec_t shutdown_delay) +{ + if (shutdown_delay) { + ngx_shutdown_idle_event.handler = ngx_shutdown_idle_timer_handler; + ngx_shutdown_idle_event.data = cycle; + ngx_shutdown_idle_event.log = cycle->log; + ngx_shutdown_idle_event.cancelable = 1; + + ngx_add_timer(&ngx_shutdown_idle_event, shutdown_delay); + } +} + + +static void +ngx_shutdown_idle_timer_handler(ngx_event_t *ev) +{ + ngx_cycle_t *cycle; + + cycle = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "shutdown idle delay timer"); + + ngx_close_idle_connections(cycle, 0); +} diff -r 7ec761f0365f -r eb0dd3d90343 src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h Thu Oct 26 23:35:09 2023 +0300 +++ b/src/core/ngx_cycle.h Wed Nov 08 07:08:11 2023 +0300 @@ -92,6 +92,7 @@ ngx_msec_t timer_resolution; ngx_msec_t shutdown_timeout; + ngx_msec_t shutdown_idle_delay; ngx_int_t worker_processes; ngx_int_t debug_points; @@ -136,6 +137,7 @@ ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag); void ngx_set_shutdown_timer(ngx_cycle_t *cycle); +void ngx_set_shutdown_idle_timer(ngx_cycle_t *cycle, ngx_msec_t shutdown_delay); extern volatile ngx_cycle_t *ngx_cycle; diff -r 7ec761f0365f -r eb0dd3d90343 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/http/ngx_http_request.c Wed Nov 08 07:08:11 2023 +0300 @@ -3282,6 +3282,7 @@ r->http_state = NGX_HTTP_KEEPALIVE_STATE; #endif + c->shutdown_delay = 1; c->idle = 1; ngx_reusable_connection(c, 1); diff -r 7ec761f0365f -r eb0dd3d90343 src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/os/unix/ngx_process_cycle.c Wed Nov 08 07:08:11 2023 +0300 @@ -698,6 +698,8 @@ static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { + ngx_core_conf_t *ccf; + ngx_int_t worker = (intptr_t) data; ngx_process = NGX_PROCESS_WORKER; @@ -733,9 +735,10 @@ if (!ngx_exiting) { ngx_exiting = 1; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_set_shutdown_timer(cycle); ngx_close_listening_sockets(cycle); - ngx_close_idle_connections(cycle); + ngx_close_idle_connections(cycle, ccf->shutdown_idle_delay); ngx_event_process_posted(cycle, &ngx_posted_events); } } diff -r 7ec761f0365f -r eb0dd3d90343 src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c Thu Oct 26 23:35:09 2023 +0300 +++ b/src/os/win32/ngx_process_cycle.c Wed Nov 08 07:08:11 2023 +0300 @@ -762,9 +762,10 @@ static ngx_thread_value_t __stdcall ngx_worker_thread(void *data) { - ngx_int_t n; - ngx_time_t *tp; - ngx_cycle_t *cycle; + ngx_int_t n; + ngx_time_t *tp; + ngx_cycle_t *cycle; + ngx_core_conf_t *ccf; tp = ngx_timeofday(); srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); @@ -801,9 +802,10 @@ if (!ngx_exiting) { ngx_exiting = 1; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_set_shutdown_timer(cycle); ngx_close_listening_sockets(cycle); - ngx_close_idle_connections(cycle); + ngx_close_idle_connections(cycle, ccf->shutdown_idle_delay); ngx_event_process_posted(cycle, &ngx_posted_events); } } _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel