From: Willy Tarreau Date: Sun, 6 Jan 2008 22:34:21 +0000 (+0100) Subject: [MEDIUM] add a turn-around state of one second after a connection failure X-Git-Tag: v1.3.15~72 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=541b5c24ca070789f2474a6c8f2398dc3877aeb5;p=thirdparty%2Fhaproxy.git [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 ef6ad1e0d1..46569a5719 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 9d7041fee6..d69d8e2eea 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -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.