diff --git a/include/types/session.h b/include/types/session.h index ef6ad1e0d..46569a571 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 9d7041fee..d69d8e2ee 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.