Implementing proxy_cache_lock when updating items


I am currently implementing a caching proxy with many short-lived items,
expiring at a specific date (Expires header set at an absolute time
10 and 30 seconds in the future by the origin). For various reasons, my
cache is multi-level (edge, intermediate 2, intermediate 1, origin) and
needs to make the items expire at the edge at 2exactly the time set in
Expires header. When the item expires, i want an updated version of the
to be available at the same URL.

I have been able to make it work, and I’m using proxy_cache_lock at
cache level to ensure i’m not hammering the origin servers nor the proxy
server. As documented, this works perfectly for items not present in the

I am also using proxy_cache_use_stale updating to avoid this hammering
in the case of already in-cache items.

My problems begin when an in-cache item expires. 2 top-level caches
name them E1,E2 for example) request an updated fragment from the below
level (INT). The fragment is requested by INT from below for the first
request, but for the second request, a stale fragment is sent (according
proxy_cache_use_stale setting, with the UPDATING status). So far, all is
working according to the docs. The problem is that fragments in the
status are stale, and cannot be cached at all by E1,E2…, and this can
very impacting for INT, because all the requests made on E1/E2 are now
proxied to INT directly, until INT has a fresh version of the item
in cache (this is quite a short duration, but in testing this generate
bursts of 15 to 50 requests in the mean time).

Is there a way to implement the proxy_cache_lock to make it work also
expired in-cache items in the configuration ? If not, can you suggest a
to implement this (i’m not familiar to nginx’s source, but i’m willing
dig into it) ?

Best regards,

Posted at Nginx Forum:,261333,261333#msg-261333


On Mon, Aug 31, 2015 at 09:16:00AM -0400, footplus wrote:

I have been able to make it work, and I’m using proxy_cache_lock at every
request, but for the second request, a stale fragment is sent (according to
to implement this (i’m not familiar to nginx’s source, but i’m willing to
dig into it) ?

Instead, you may consider using “proxy_cache_use_stale updating”
in combination with one of the following:

  • Return some fixed short expiration time for stale responses
    returned by INT. This will ensure that edge servers will cache
    it for at least some time, and won’t try to request new versions
    over and over.

    I should be possible to do so with the “expires” directive and a
    map{} from $upstream_cache_status, e.g.:

    map $upstream_cache_status $expires {
        default                "";
        STALE                  "10s";
    expires $expires;

    Alternatively, if your edge servers use nginx, you can do

    map $upstream_cache_status $expires {
        default                "";
        STALE                  "10";
    add_header X-Accel-Expires $expires;

    and it will apply to edge servers only, and won’t try to change
    any other response headers.

  • Ensure that the version cached by INT will be considered stale
    before it will become uncacheable according to HTTP headers.
    This can be done either with proxy_ignore_headers +
    proxy_cache_valid, or using the X-Accel-Expires header returned
    by backends.

Maxim D.

Thanks for your reply.

I’m currently using this mechanism (small variation of yours) to work
the limitation. On every intermediate cache server, i’m using the
(whole chain is using nginx).

    map $upstream_cache_status 

default “”;

    more_set_headers "X-Accel-Expires:


(the key is using UPDATING also, because proxy_cache_use_stale is set to
updating only on our setup).

So far I think we can manage to use this work-around for our setup, but
has the drawback of potentially serving slightly out of date content.

In our case, said items are ~1k files, with a TTL of 2~10s, and they
fresh for our apps to work correctly. We’re considering using an
“freshener” on intermediary caches, but i fear we can’t very efficiently
this in our case, due to the nature of these files (HLS video playlists,
locations and bitrates changing upon business decisions). Also, it would
be very practical to refresh hundreds of files with 2s TTL at 1s
on 3 cache layers, if as we expect a good part of them are not always
by upstream.

Thanks for the suggestion.
I’m still looking for a way to hard lock the updating items however :slight_smile:

Best regards,

Posted at Nginx Forum:,261333,261402#msg-261402

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs