# HG changeset patch # User Roman Arutyunyan # Date 1495717079 -10800 # Node ID 9552758a786e20c70130427298895bc782a754c5 # Parent 3e2d90073adf1ee828052834266ec4d81fc58892 Background subrequests for cache updates. Previously, cache background update might not work as expected, making client wait for it to complete before receiving the final part of a stale response. This could happen if the response could not be sent to the client socket in one filter chain call. Now background cache update is done in a background subrequest. This type of subrequest does not block any other subrequests or the main request. diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2518,6 +2518,7 @@ ngx_http_subrequest(ngx_http_request_t * sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0; sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0; + sr->background = (flags & NGX_HTTP_SUBREQUEST_BACKGROUND) != 0; sr->unparsed_uri = r->unparsed_uri; sr->method_name = ngx_http_core_get_method; @@ -2531,29 +2532,31 @@ ngx_http_subrequest(ngx_http_request_t * sr->read_event_handler = ngx_http_request_empty_handler; sr->write_event_handler = ngx_http_handler; - if (c->data == r && r->postponed == NULL) { - c->data = sr; - } - sr->variables = r->variables; sr->log_handler = r->log_handler; - pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); - if (pr == NULL) { - return NGX_ERROR; - } - - pr->request = sr; - pr->out = NULL; - pr->next = NULL; - - if (r->postponed) { - for (p = r->postponed; p->next; p = p->next) { /* void */ } - p->next = pr; - - } else { - r->postponed = pr; + if (!sr->background) { + if (c->data == r && r->postponed == NULL) { + c->data = sr; + } + + pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } + + pr->request = sr; + pr->out = NULL; + pr->next = NULL; + + if (r->postponed) { + for (p = r->postponed; p->next; p = p->next) { /* void */ } + p->next = pr; + + } else { + r->postponed = pr; + } } sr->internal = 1; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2357,6 +2357,26 @@ ngx_http_finalize_request(ngx_http_reque } if (r != r->main) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->background) { + if (!r->logged) { + if (clcf->log_subrequest) { + ngx_http_log_request(r); + } + + r->logged = 1; + + } else { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "subrequest: \"%V?%V\" logged again", + &r->uri, &r->args); + } + + r->done = 1; + ngx_http_finalize_connection(r); + return; + } if (r->buffered || r->postponed) { @@ -2374,9 +2394,6 @@ ngx_http_finalize_request(ngx_http_reque r->main->count--; if (!r->logged) { - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (clcf->log_subrequest) { ngx_http_log_request(r); } @@ -2440,6 +2457,8 @@ ngx_http_finalize_request(ngx_http_reque } r->done = 1; + + r->read_event_handler = ngx_http_block_reading; r->write_event_handler = ngx_http_request_empty_handler; if (!r->post_action) { @@ -2558,6 +2577,8 @@ ngx_http_finalize_connection(ngx_http_re return; } + r = r->main; + if (r->reading_body) { r->keepalive = 0; r->lingering_close = 1; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -64,6 +64,7 @@ #define NGX_HTTP_SUBREQUEST_IN_MEMORY 2 #define NGX_HTTP_SUBREQUEST_WAITED 4 #define NGX_HTTP_SUBREQUEST_CLONE 8 +#define NGX_HTTP_SUBREQUEST_BACKGROUND 16 #define NGX_HTTP_LOG_UNSAFE 1 @@ -486,7 +487,6 @@ struct ngx_http_request_s { #if (NGX_HTTP_CACHE) unsigned cached:1; - unsigned cache_updater:1; #endif #if (NGX_HTTP_GZIP) @@ -543,6 +543,7 @@ struct ngx_http_request_s { unsigned stat_writing:1; unsigned stat_processing:1; + unsigned background:1; unsigned health_check:1; /* used to parse HTTP headers */ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -879,7 +879,7 @@ ngx_http_upstream_cache(ngx_http_request case NGX_HTTP_CACHE_STALE: if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) - || c->stale_updating) && !r->cache_updater + || c->stale_updating) && !r->background && u->conf->cache_background_update) { r->cache->background = 1; @@ -892,7 +892,7 @@ ngx_http_upstream_cache(ngx_http_request case NGX_HTTP_CACHE_UPDATING: if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) - || c->stale_updating) && !r->cache_updater) + || c->stale_updating) && !r->background) { u->cache_status = rc; rc = NGX_OK; @@ -1076,14 +1076,14 @@ ngx_http_upstream_cache_background_updat } if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, - NGX_HTTP_SUBREQUEST_CLONE) + NGX_HTTP_SUBREQUEST_CLONE + |NGX_HTTP_SUBREQUEST_BACKGROUND) != NGX_OK) { return NGX_ERROR; } sr->header_only = 1; - sr->cache_updater = 1; return NGX_OK; }