[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.
This commit is contained in:
Willy Tarreau 2008-01-06 23:34:21 +01:00
parent 25b501a6b1
commit 541b5c24ca
2 changed files with 31 additions and 11 deletions

View 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 */

View 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.