When SIGUSR1 is received, haproxy enters in soft-stop and quits when no connection remains. It can happen that the instance remains alive for a long time, depending on timeouts and traffic. This option ensures that soft-stop won't run for too long.
Example: global hard-stop-after 30s # Once in soft-stop, the instance will remain # alive for at most 30 seconds. --- doc/configuration.txt | 17 +++++++++++++++++ include/types/global.h | 2 ++ src/cfgparse.c | 17 +++++++++++++++++ src/haproxy.c | 3 ++- src/proxy.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 1 deletion(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 73a4f4b8..fb3e691d 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -536,6 +536,7 @@ The following keywords are supported in the "global" section : - external-check - gid - group + - hard-stop-after - log - log-tag - log-send-hostname @@ -703,6 +704,22 @@ gid <number> will only be able to drop these groups if started with superuser privileges. See also "group" and "uid". +hard-stop-after <time> + Defines the maximum time allowed to perform a clean soft-stop. + + Arguments : + <time> is the maximum time (by default in milliseconds) for which the + instance will remain alive when a soft-stop is received via the + SIGUSR1 signal. + + This may be used to ensure that the instance will quit even if connections + remain opened during a soft-stop (for example with long timeouts for a proxy + in tcp mode). It applies both in TCP and HTTP mode. + + Example: + global + hard-stop-after 30s + group <group name> Similar to "gid" but uses the GID of group name <group name> from /etc/group. See also "gid" and "user". diff --git a/include/types/global.h b/include/types/global.h index e14a2add..8330ec0a 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -80,6 +80,7 @@ struct global { int gid; int external_check; int nbproc; + unsigned int hard_stop_after; /* maximum time allowed to perform a soft-stop */ int maxconn, hardmaxconn; int maxsslconn; int ssl_session_max_cost; /* how many bytes an SSL session may cost */ @@ -194,6 +195,7 @@ static inline int already_warned(unsigned int warning) return 0; } +void deinit(void); void hap_register_build_opts(const char *str, int must_free); void hap_register_post_check(int (*fct)()); void hap_register_post_deinit(void (*fct)()); diff --git a/src/cfgparse.c b/src/cfgparse.c index 2eb25edb..9681e06b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1011,6 +1011,23 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } } /* end of user/group name handling*/ + else if (strcmp(args[0], "hard-stop-after") == 0) { + const char *res; + + if (!*args[1]) { + Alert("parsing [%s:%d] : '%s' expects <time> as argument.\n", + file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + res = parse_time_err(args[1], &global.hard_stop_after, TIME_UNIT_MS); + if (res) { + Alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n", + file, linenum, *res, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } else if (!strcmp(args[0], "nbproc")) { if (alertif_too_many_args(1, file, linenum, args, &err_code)) goto out; diff --git a/src/haproxy.c b/src/haproxy.c index 559b4811..71015cc1 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -117,6 +117,7 @@ int relative_pid = 1; /* process id starting at 1 */ /* global options */ struct global global = { + .hard_stop_after = TICK_ETERNITY, .nbproc = 1, .req_count = 0, .logsrvs = LIST_HEAD_INIT(global.logsrvs), @@ -1225,7 +1226,7 @@ static void deinit_stick_rules(struct list *rules) } } -static void deinit(void) +void deinit(void) { struct proxy *p = proxy, *p0; struct cap_hdr *h,*h_next; diff --git a/src/proxy.c b/src/proxy.c index 19eddcac..8a8b5406 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -914,6 +914,29 @@ struct task *manage_proxy(struct task *t) } +struct task *hard_stop(struct task *t) +{ + struct proxy *p; + struct stream *s; + + Warning("soft-stop running for too long, performing a hard-stop.\n"); + send_log(NULL, LOG_WARNING, "soft-stop running for too long, performing a hard-stop.\n"); + p = proxy; + while (p) { + if (!(p->cap & PR_CAP_FE)) + continue; + + list_for_each_entry(s, &streams, list) { + stream_shutdown(s, SF_ERR_KILLED); + } + p = p->next; + } + + /* Do some cleanup and explicitely quit */ + deinit(); + exit(0); +} + /* * this function disables health-check servers so that the process will quickly be ignored * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace @@ -923,8 +946,19 @@ void soft_stop(void) { struct proxy *p; struct peers *prs; + struct task *task; stopping = 1; + if (tick_isset(global.hard_stop_after)) { + task = task_new(); + if (task) { + task->process = hard_stop; + task_schedule(task, tick_add(now_ms, global.hard_stop_after)); + } + else { + Alert("out of memory trying to allocate the hard-stop task.\n"); + } + } p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { -- 2.11.0