#define SRV_BIND_SRC 0x0008 /* this server uses a specific source address */
#define SRV_CHECKED 0x0010 /* this server needs to be checked */
#define SRV_GOINGDOWN 0x0020 /* this server says that it's going down (404) */
+#define SRV_WARMINGUP 0x0040 /* this server is warming up after a failure */
#define SRV_TPROXY_ADDR 0x0020 /* bind to this non-local address to reach this server */
#define SRV_TPROXY_CIP 0x0040 /* bind to the client's IP address to reach this server */
int health; /* 0->rise-1 = bad; rise->rise+fall-1 = good */
int rise, fall; /* time in iterations */
int inter; /* time in milliseconds */
+ int slowstart; /* slowstart time in seconds (ms in the conf) */
int result; /* health-check result : SRV_CHK_* */
int curfd; /* file desc used for current test, or -1 if not in test */
newsrv->health = newsrv->rise; /* up, but will fall down at first failure */
newsrv->uweight = 1;
newsrv->maxqueue = 0;
+ newsrv->slowstart = 0;
cur_arg = 3;
while (*args[cur_arg]) {
newsrv->maxqueue = atol(args[cur_arg + 1]);
cur_arg += 2;
}
+ else if (!strcmp(args[cur_arg], "slowstart")) {
+ /* slowstart is stored in seconds */
+ newsrv->slowstart = (atol(args[cur_arg + 1]) + 999) / 1000;
+ cur_arg += 2;
+ }
else if (!strcmp(args[cur_arg], "check")) {
global.maxsock++;
do_check = 1;
}
#endif
else {
- Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', and 'weight'.\n",
+ Alert("parsing [%s:%d] : server %s only supports options 'backup', 'cookie', 'check', 'inter', 'rise', 'fall', 'addr', 'port', 'source', 'minconn', 'maxconn', 'maxqueue', 'slowstart' and 'weight'.\n",
file, linenum, newsrv->id);
return -1;
}
if ((s->result & (SRV_CHK_ERROR|SRV_CHK_RUNNING)) == SRV_CHK_RUNNING) { /* good server detected */
//fprintf(stderr, "process_chk: 9\n");
+ if (s->state & SRV_WARMINGUP) {
+ if (now.tv_sec < s->last_change || now.tv_sec >= s->last_change + s->slowstart) {
+ s->state &= ~SRV_WARMINGUP;
+ if (s->proxy->lbprm.algo & BE_LB_PROP_DYN)
+ s->eweight = s->uweight * BE_WEIGHT_SCALE;
+ if (s->proxy->lbprm.update_server_eweight)
+ s->proxy->lbprm.update_server_eweight(s);
+ }
+ else if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) {
+ /* for dynamic algorithms, let's update the weight */
+ s->eweight = BE_WEIGHT_SCALE * (now.tv_sec - s->last_change) / s->slowstart;
+ s->eweight *= s->uweight;
+ if (s->proxy->lbprm.update_server_eweight)
+ s->proxy->lbprm.update_server_eweight(s);
+ }
+ /* probably that we can refill this server with a bit more connections */
+ check_for_pending(s);
+ }
+
/* we may have to add/remove this server from the LB group */
if ((s->state & SRV_RUNNING) && (s->proxy->options & PR_O_DISABLE404)) {
if ((s->state & SRV_GOINGDOWN) &&
s->last_change = now.tv_sec;
s->state |= SRV_RUNNING;
+ if (s->slowstart > 0) {
+ s->state |= SRV_WARMINGUP;
+ if (s->proxy->lbprm.algo & BE_LB_PROP_DYN) {
+ /* For dynamic algorithms, start at the first step of the weight,
+ * without multiplying by BE_WEIGHT_SCALE.
+ */
+ s->eweight = s->uweight;
+ if (s->proxy->lbprm.update_server_eweight)
+ s->proxy->lbprm.update_server_eweight(s);
+ }
+ }
s->proxy->lbprm.set_server_status_up(s);
/* check if we can handle some connections queued at the proxy. We
/* returns the effective dynamic maxconn for a server, considering the minconn
* and the proxy's usage relative to its dynamic connections limit. It is
- * expected that 0 < s->minconn <= s->maxconn when this is called.
+ * expected that 0 < s->minconn <= s->maxconn when this is called. If the
+ * server is currently warming up, the slowstart is also applied to the
+ * resulting value, which can be lower than minconn in this case, but never
+ * less than 1.
*/
unsigned int srv_dynamic_maxconn(const struct server *s)
{
+ unsigned int max;
+
if (s->proxy->beconn >= s->proxy->fullconn)
/* no fullconn or proxy is full */
- return s->maxconn;
-
- if (s->minconn == s->maxconn)
+ max = s->maxconn;
+ else if (s->minconn == s->maxconn)
/* static limit */
- return s->maxconn;
-
- return MAX(s->minconn,
- s->proxy->beconn * s->maxconn / s->proxy->fullconn);
+ max = s->maxconn;
+ else max = MAX(s->minconn,
+ s->proxy->beconn * s->maxconn / s->proxy->fullconn);
+
+ if ((s->state & SRV_WARMINGUP) &&
+ now.tv_sec < s->last_change + s->slowstart &&
+ now.tv_sec >= s->last_change) {
+ unsigned int ratio;
+ ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart);
+ max = max * ratio / 100;
+ }
+ return max;
}