Due to issues with a backend beyond my influence i need to fix this with
Nginx.
Root-Cause: A CMS generates empty files on a filesystem which will be
later
filled with content. However: those files are there for some time with 0
bytes
and will be served with 200 through a chain of a caching Nginx and a
caching
CDN.
The Backend-Filesystem is served by a Nginx. Solution could be to serve
a
404
for all empty files. I tried with $sent_http_content_length, but it
seems
to
be empty in the location where i would need it. Is it possible to use
some
kind of ‘test -s’ on the file to decide when to send a 404?
I also tried to tackle it in the caching SlowFS-Nginx, by using
$upstream_http_content_length in if or map-statements [1]. I can see
$upstream_http_content_length set in an X-Debug-Header i added, but
can’t
get
it to work to use it to act on it.
if ($upstream_http_content_length = 0) {
return 404;
}
I found the discussion about ‘using $upstream* variables inside map
directive’[2]
but even if i would get this to work it wouldn’t be enough as i need to
signal the CDN in front (with some headers) that it also should not
cache
the
empty response. Best would be to generate a 404 if the upstream-object
is
empty.
So maybe someone here has an idea how to tackle this.
The Backend-Filesystem is served by a Nginx. Solution could be to serve a
404
for all empty files.
Please note that this is not a solution, as at some point files
will be partially filled with content, and testing that the size
isn’t 0 won’t help. Rather, it’s a workaround which hides the
problem in some cases.
The only solution I see is to fix backend to update files
atomically - e.g., write to a temporaty file, and then rename()
it to a real name.
I tried with $sent_http_content_length, but it seems to
be empty in the location where i would need it. Is it possible to use some
kind of ‘test -s’ on the file to decide when to send a 404?
This is something possible with embedded perl (and lua, as already
suggested).
I also tried to tackle it in the caching SlowFS-Nginx, by using
$upstream_http_content_length in if or map-statements [1]. I can see
$upstream_http_content_length set in an X-Debug-Header i added, but can’t
get
it to work to use it to act on it.
if ($upstream_http_content_length = 0) {
return 404;
}
This is not going to work as “if” will be executed before the
request is sent to the upstream server.
Removing proxy_cache_bypass should fix things for you.
The problem is that proxy_cache_bypass will be evaluated before a
request is sent to upstream and therefore before
$upstream_http_content_length will be available. As a result
$flag_cache_empty will be always 0. And, because map results are
cached for entire request lifetime, proxy_no_cache will see the
same value, 0.