[MEDIUM] add a turn-around state of one second after a connection failure
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.
diff --git a/include/types/session.h b/include/types/session.h
index ef6ad1e..46569a5 100644
--- a/include/types/session.h
+++ b/include/types/session.h
@@ -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 */
diff --git a/src/proto_http.c b/src/proto_http.c
index 9d7041f..d69d8e2 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2488,18 +2488,38 @@
/* 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.