[PATCH] Do not break downstream connection on proxy_cache write error

Kipras Mancevicius kiprasm at gmail.com
Mon May 2 13:36:09 UTC 2022


# HG changeset patch
# User Kipras Mancevicius <kiprasm at gmail.com>
# Date 1651495240 -10800
#      Mon May 02 15:40:40 2022 +0300
# Branch proxy_cache_write_disk_full_fix
# Node ID e6e708fd7958987027f6de7748d948e5015ed32b
# Parent  a736a7a613ea6e182ff86fbadcb98bb0f8891c0b
Do not break downstream connection on proxy_cache write error

Continue sending response to downstream connection and delete temp cache file on
upstream connection finalization.

diff -r a736a7a613ea -r e6e708fd7958 src/core/ngx_file.c
--- a/src/core/ngx_file.c	Tue Feb 08 17:35:27 2022 +0300
+++ b/src/core/ngx_file.c	Mon May 02 15:40:40 2022 +0300
@@ -765,6 +765,13 @@
                               ngx_delete_file_n " \"%s\" failed", name);
 
             }
+        } else {
+            /*
+             * if the file failed to fully copy (e.g. target disk is full) - it
+             * may remain (partially written) in the target disk. Attempt to
+             * delete it.
+             */
+            ngx_delete_file(name);
         }
 
         ngx_free(name);
diff -r a736a7a613ea -r e6e708fd7958 src/event/ngx_event_pipe.c
--- a/src/event/ngx_event_pipe.c	Tue Feb 08 17:35:27 2022 +0300
+++ b/src/event/ngx_event_pipe.c	Mon May 02 15:40:40 2022 +0300
@@ -753,10 +753,21 @@
         out = p->writing;
         p->writing = NULL;
 
-        n = ngx_write_chain_to_temp_file(p->temp_file, NULL);
+        /*
+         * stop writing to cache on cache write fail, but keep sending response
+         * downstream. Incomplete temp cache file will be deleted later.
+         */
+        if (p->cache_write_fail) {
+            return NGX_BUSY;
+        } else {
+            n = ngx_write_chain_to_temp_file(p->temp_file, NULL);
 
-        if (n == NGX_ERROR) {
-            return NGX_ABORT;
+            if (n == NGX_ERROR) {
+                p->cache_write_fail = 1;
+                p->cacheable = 0;
+
+                return NGX_BUSY;
+            }
         }
 
         goto done;
@@ -777,6 +788,23 @@
         out = p->in;
     }
 
+    /*
+     * stop writing to cache on cache write fail, but keep sending response
+     * downstream. Incomplete temp cache file will be deleted later.
+     */
+    if (p->cache_write_fail) {
+        return NGX_BUSY;
+    } else {
+        n = ngx_write_chain_to_temp_file(p->temp_file, out);
+
+        if (n == NGX_ERROR) {
+            p->cache_write_fail = 1;
+            p->cacheable = 0;
+
+            return NGX_BUSY;
+        }
+    }
+
     if (!p->cacheable) {
 
         size = 0;
diff -r a736a7a613ea -r e6e708fd7958 src/event/ngx_event_pipe.h
--- a/src/event/ngx_event_pipe.h	Tue Feb 08 17:35:27 2022 +0300
+++ b/src/event/ngx_event_pipe.h	Mon May 02 15:40:40 2022 +0300
@@ -66,6 +66,7 @@
     unsigned           downstream_error:1;
     unsigned           cyclic_temp_file:1;
     unsigned           aio:1;
+    unsigned           cache_write_fail:1;
 
     ngx_int_t          allocated;
     ngx_bufs_t         bufs;
diff -r a736a7a613ea -r e6e708fd7958 src/http/ngx_http_file_cache.c
--- a/src/http/ngx_http_file_cache.c	Tue Feb 08 17:35:27 2022 +0300
+++ b/src/http/ngx_http_file_cache.c	Mon May 02 15:40:40 2022 +0300
@@ -1377,6 +1377,16 @@
 
     cache = c->file_cache;
 
+    if (r->upstream && r->upstream->pipe && r->upstream->pipe->cache_write_fail) {
+        /*
+         * if cache file failed to be written (e.g. cache disk is full) - we
+         * kept sending response downstream and then delete the incomplete temp
+         * cache file here (after response is served downstream).
+         */
+        ngx_http_file_cache_free(cache, tf);
+        return;
+    }
+
     c->updated = 1;
     c->updating = 0;
 



More information about the nginx-devel mailing list