# HG changeset patch # User Maxim Dounin # Date 1488901876 -10800 # Node ID 97c99bb4373718d6d85fff79afd35e377b1a2466 # Parent 3069dd358ba24d675e786c49270c29fb89b34be9 Introduced worker_shutdown_timeout. The directive configures a timeout to be used when gracefully shutting down worker processes. When the timer expires, nginx will try to close all the connections currently open to facilitate shutdown. diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -124,6 +124,13 @@ static ngx_command_t ngx_core_commands[ offsetof(ngx_core_conf_t, rlimit_core), NULL }, + { ngx_string("worker_shutdown_timeout"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + 0, + offsetof(ngx_core_conf_t, shutdown_timeout), + NULL }, + { ngx_string("working_directory"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -1014,6 +1021,7 @@ ngx_core_module_create_conf(ngx_cycle_t ccf->daemon = NGX_CONF_UNSET; ccf->master = NGX_CONF_UNSET; ccf->timer_resolution = NGX_CONF_UNSET_MSEC; + ccf->shutdown_timeout = NGX_CONF_UNSET_MSEC; ccf->worker_processes = NGX_CONF_UNSET; ccf->debug_points = NGX_CONF_UNSET; @@ -1042,6 +1050,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c ngx_conf_init_value(ccf->daemon, 1); 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_value(ccf->worker_processes, 1); ngx_conf_init_value(ccf->debug_points, 0); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -15,6 +15,7 @@ static ngx_int_t ngx_init_zone_pool(ngx_ ngx_shm_zone_t *shm_zone); 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); volatile ngx_cycle_t *ngx_cycle; @@ -22,6 +23,7 @@ ngx_array_t ngx_old_cycles; static ngx_pool_t *ngx_temp_pool; static ngx_event_t ngx_cleaner_event; +static ngx_event_t ngx_shutdown_event; ngx_uint_t ngx_test_config; ngx_uint_t ngx_dump_config; @@ -1333,3 +1335,54 @@ ngx_clean_old_cycles(ngx_event_t *ev) ngx_old_cycles.nelts = 0; } } + + +void +ngx_set_shutdown_timer(ngx_cycle_t *cycle) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ccf->shutdown_timeout) { + ngx_shutdown_event.handler = ngx_shutdown_timer_handler; + ngx_shutdown_event.data = cycle; + ngx_shutdown_event.log = cycle->log; + ngx_shutdown_event.cancelable = 1; + + ngx_add_timer(&ngx_shutdown_event, ccf->shutdown_timeout); + } +} + + +static void +ngx_shutdown_timer_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_cycle_t *cycle; + ngx_connection_t *c; + + cycle = ev->data; + + c = cycle->connections; + + for (i = 0; i < cycle->connection_n; i++) { + + if (c[i].fd == (ngx_socket_t) -1 + || c[i].read == NULL + || c[i].read->accept + || c[i].read->channel + || c[i].read->resolver) + { + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, + "*%uA shutdown timeout", c[i].number); + + c[i].close = 1; + c[i].error = 1; + + c[i].read->handler(c[i].read); + } +} diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -88,6 +88,7 @@ typedef struct { ngx_flag_t master; ngx_msec_t timer_resolution; + ngx_msec_t shutdown_timeout; ngx_int_t worker_processes; ngx_int_t debug_points; @@ -129,6 +130,7 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_ ngx_cpuset_t *ngx_get_cpu_affinity(ngx_uint_t n); 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); extern volatile ngx_cycle_t *ngx_cycle; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -763,6 +763,7 @@ ngx_worker_process_cycle(ngx_cycle_t *cy if (!ngx_exiting) { ngx_exiting = 1; + ngx_set_shutdown_timer(cycle); ngx_close_listening_sockets(cycle); ngx_close_idle_connections(cycle); } diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -800,6 +800,7 @@ ngx_worker_thread(void *data) if (!ngx_exiting) { ngx_exiting = 1; + ngx_set_shutdown_timer(cycle); ngx_close_listening_sockets(cycle); ngx_close_idle_connections(cycle); }