[nginx] Introduced worker_shutdown_timeout.

Datong Sun datong at cloudflare.com
Wed Mar 8 23:40:47 UTC 2017


Hello!

Looks like to me that the original patch does what it's supposed to do
(when combined with http://hg.nginx.org/nginx/rev/3069dd358ba2). Here is my
understanding:

Before this patch, an active connection could potentially delay shutdown
indefinitely due to the presence of connection related timer inside the
timer tree. The only reason why ngx_shutdown_timer_handler has to be
invoked would be to force those lingering connections to be closed and
therefore, free-up the timer tree and allow the shutdown to finish.

If all connections were closed before ngx_shutdown_timer_handler was fired
(your case), it is already safe to finish the shutdown and there is no
reason to invoke or wait for ngx_shutdown_timer_handler to fire anymore.
 The cancelable field makes sure when this happens ngx_shutdown_event does
not prevent NGINX from being able to complete the shutdown.

Seems to me that delaying the shutdown until worker_shutdown_timeout when
there is already no active connection left makes little sense.

Thanks,
Datong

On Tue, Mar 7, 2017 at 11:52 PM, 洪志道 <hongzhidao at gmail.com> wrote:

> Hi!
>
> It's a good design.
> It seems the worker process is not killed until expired, the time is set
> by 'worker_shutdown_timeout'.
> But I think ngx_shutdown_timer_handler will never be called, because of
> the following deal.
>
>        if (ngx_exiting) {
>             if (ngx_event_no_timers_left() == NGX_OK) {
>                 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
>                 ngx_worker_process_exit(cycle);  // the worker process
> exits though there are cancelable timers such as ngx_shutdown_event.
>             }
>         }
>
> I'm not sure it's right?
>
> diff -r d45072375572 src/core/ngx_cycle.c
> --- a/src/core/ngx_cycle.c Tue Mar 07 18:51:17 2017 +0300
> +++ b/src/core/ngx_cycle.c Sun Mar 05 17:03:22 2017 +0800
> @@ -1348,7 +1348,6 @@
>          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);
>      }
>
> And I think it's better that the shutting down process keep alive until '
> worker_shutdown_timeout'.
>
> Thanks.
> B.R.
>
> 2017-03-08 1:01 GMT+08:00 Maxim Dounin <mdounin at mdounin.ru>:
>
>> details:   http://hg.nginx.org/nginx/rev/97c99bb43737
>> branches:
>> changeset: 6930:97c99bb43737
>> user:      Maxim Dounin <mdounin at mdounin.ru>
>> date:      Tue Mar 07 18:51:16 2017 +0300
>> description:
>> 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.
>>
>> diffstat:
>>
>>  src/core/nginx.c                 |   9 ++++++
>>  src/core/ngx_cycle.c             |  53 ++++++++++++++++++++++++++++++
>> ++++++++++
>>  src/core/ngx_cycle.h             |   2 +
>>  src/os/unix/ngx_process_cycle.c  |   1 +
>>  src/os/win32/ngx_process_cycle.c |   1 +
>>  5 files changed, 66 insertions(+), 0 deletions(-)
>>
>> diffs (148 lines):
>>
>> 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);
>>              }
>> _______________________________________________
>> nginx-devel mailing list
>> nginx-devel at nginx.org
>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>
>
>
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>



-- 

*Datong Sun*  |  Systems Engineer
datong at cloudflare.com
<https://www.cloudflare.com/>

1 888 99 FLARE  |  www.cloudflare.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20170308/e7a0a239/attachment.html>


More information about the nginx-devel mailing list