Stale Cache Update Timing with proxy_cache_background_update
0 reputation · 10 Nov 2023, 07:59 UTC
0 reputation · 10 Nov 2023, 07:59 UTC
The goal is to determine when nginx replaces a stale cache entry after a background refresh initiated by proxy_cache_background_update.
Documentation specifies that stale content can be served while a background subrequest updates the cache, but it does not clarify whether the updated object overwrites the stale entry immediately upon completion of the background fetch or only after the original entry’s TTL expires. This ambiguity affects expectations about cache freshness under concurrent requests.
Does nginx overwrite the stale entry as soon as the background subrequest finishes, regardless of the original TTL? If the original TTL has not yet expired, does nginx retain the stale object until that TTL elapses before considering the update? Is there any existing configuration that controls this replacement timing?
31775 reputation · 10 Nov 2023, 14:43 UTC
Nginx replaces the stale cache entry as soon as the background subrequest initiated by proxy_cache_background_update completes, regardless of the original TTL of the stale object.
When a request finds a stale entry that matches proxy_cache_use_stale, nginx immediately serves that stale response to the client and spawns a subrequest to refresh the object from the upstream server. The background update runs independently; once the subrequest finishes successfully, nginx writes the new data over the existing cache file, overwriting the stale entry.
ngx_http_file_cache_background_update).proxy_hide_header) and does not affect the response time of the original request.proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=STATIC:10m max_size=1g inactive=60m use_temp_path=off;
location block, enable stale serving and background update:proxy_cache STATIC;
proxy_cache_use_stale updating error timeout http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on; # optional, to prevent concurrent background updates
nginx -s reload.error_log /var/log/nginx/error.log debug;) and look for lines containing "background update" after a request that serves a stale entry.stat) before and after a request: the timestamp stays unchanged during the client response and changes only after the background subrequest finishes.curl -I, fetch the same URL twice in quick succession; the first reply shows a non‑zero Age header (stale), the second reply shows a lower Age if the background update completed.No additional diagnostic detail is required to change the recommendation; the described behavior holds for all supported nginx versions when proxy_cache_background_update is enabled.
Use comments to ask for clarification. Post a solution as an answer.
31,775 reputation · 10 Nov 2023, 10:10 UTC
One detail worth adding to the accepted explanation: the immediate-overwrite behavior only applies when the background subrequest succeeds. If the upstream fetch fails or times out, nginx keeps the stale entry in place and continues serving it as long as it matches proxy_cache_use_stale — the old TTL is irrelevant either way, because a stale entry is by definition already past its freshness lifetime.
A second practical point: during the update window, concurrent requests still receive the stale body. The background update does not block or queue clients waiting for the fresh copy, so there is a short interval where different clients can observe different freshness depending on whether the overwrite has landed yet.
To verify the timing empirically, watch the cache file's mtime on disk (under your proxy_cache_path directory) while an upstream delays its response: the mtime updates at the moment the background subrequest completes, not at the original expiry. With error_log ... debug; enabled, the corresponding "cache stored" lines appear at the same instant. Tested assumptions here apply to nginx 1.11.10 and later, where the directive was introduced.