]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add a turn-around state of one second after a connection failure
authorWilly Tarreau <w@1wt.eu>
Sun, 6 Jan 2008 22:34:21 +0000 (23:34 +0100)
committerWilly Tarreau <w@1wt.eu>
Sun, 6 Jan 2008 22:34:21 +0000 (23:34 +0100)
Several users have complained that when haproxy gets a connection
failure due to an active reject from a server, it immediately
retries, often leading to the same situation being repeated until
the retry counter reaches zero.

Now if a connection error shows up, a turn-around state of 1 second
is applied before retrying. This is performed by faking a connection
timeout in order not to touch much code. However, a cleaner method
would involve an extra state.

include/types/session.h
src/proto_http.c

index ef6ad1e0d1881df43d021927f43887fe274bc31c..46569a5719bdbaedf9f1bb593d52688057a0fcab 100644 (file)
@@ -49,7 +49,7 @@
 #define SN_SELF_GEN    0x00000040      /* the proxy generates data for the client (eg: stats) */
 #define SN_FRT_ADDR_SET        0x00000080      /* set if the frontend address has been filled */
 #define SN_REDISP      0x00000100      /* set if this session was redispatched from one server to another */
-/* unused:              0x00000200 */
+#define SN_CONN_TAR    0x00000200      /* set if this session is turning around before reconnecting */
 /* unused:              0x00000400 */
 /* unused:              0x00000800 */
 
index 9d7041fee627683187521514955fde4c10642d75..d69d8e2eeaddc823eee3b72f368ff7844d23c0d7 100644 (file)
@@ -2488,18 +2488,38 @@ int process_srv(struct session *t)
                        /* timeout, asynchronous connect error or first write error */
                        //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
 
-                       fd_delete(t->srv_fd);
-                       if (t->srv)
-                               t->srv->cur_sess--;
+                       if (t->flags & SN_CONN_TAR) {
+                               /* We are doing a turn-around waiting for a new connection attempt. */
+                               if (!tv_isle(&req->cex, &now))
+                                       return 0;
+                               t->flags &= ~SN_CONN_TAR;
+                       }
+                       else {
+                               fd_delete(t->srv_fd);
+                               if (t->srv)
+                                       t->srv->cur_sess--;
 
-                       if (!(req->flags & BF_WRITE_STATUS))
-                               conn_err = SN_ERR_SRVTO; // it was a connect timeout.
-                       else
-                               conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
+                               if (!(req->flags & BF_WRITE_STATUS))
+                                       conn_err = SN_ERR_SRVTO; // it was a connect timeout.
+                               else
+                                       conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
 
-                       /* ensure that we have enough retries left */
-                       if (srv_count_retry_down(t, conn_err))
-                               return 1;
+                               /* ensure that we have enough retries left */
+                               if (srv_count_retry_down(t, conn_err))
+                                       return 1;
+
+                               if (req->flags & BF_WRITE_ERROR) {
+                                       /* we encountered an immediate connection error, and we
+                                        * will have to retry connecting to the same server, most
+                                        * likely leading to the same result. To avoid this, we
+                                        * fake a connection timeout to retry after a turn-around
+                                        * time of 1 second. We will wait in the previous if block.
+                                        */
+                                       t->flags |= SN_CONN_TAR;
+                                       tv_ms_add(&req->cex, &now, 1000);
+                                       return 0;
+                               }
+                       }
 
                        if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
                                /* We're on our last chance, and the REDISP option was specified.