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