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


Reply via email to