Several use cases may accept to abruptly close the connections when the
instance is stopping instead of waiting for timeouts to happen.
This option allows to specify a grace period which defines the maximum
time to spend to perform a soft-stop (occuring when SIGUSR1 is
received).

With this global option defined in the configuration, once all connections are
closed or the grace time is reached, the instance will quit.
---
 doc/configuration.txt  | 12 ++++++++++++
 include/types/global.h |  2 ++
 src/cfgparse.c         | 17 +++++++++++++++++
 src/haproxy.c          |  8 ++++++++
 src/proxy.c            |  2 ++
 5 files changed, 41 insertions(+)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 228e8132..b1109906 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -535,6 +535,7 @@ The following keywords are supported in the "global" 
section :
    - deviceatlas-properties-cookie
    - external-check
    - gid
+   - grace
    - group
    - log
    - log-tag
@@ -703,6 +704,17 @@ gid <number>
   will only be able to drop these groups if started with superuser privileges.
   See also "group" and "uid".
 
+grace <time>
+  Defines the grace 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 (for example with long timeouts for a proxy in tcp mode).
+
 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..1d273bf4 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 grace;         /* grace period to process soft stop */
        int maxconn, hardmaxconn;
        int maxsslconn;
        int ssl_session_max_cost;   /* how many bytes an SSL session may cost */
@@ -170,6 +171,7 @@ extern const int zero;
 extern const int one;
 extern const struct linger nolinger;
 extern int stopping;   /* non zero means stopping in progress */
+extern int grace;
 extern char hostname[MAX_HOSTNAME_LEN];
 extern char localpeer[MAX_HOSTNAME_LEN];
 extern struct list global_listener_queue; /* list of the temporarily limited 
listeners */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 2eb25edb..8b6855f7 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], "grace") == 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.grace, 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..400fb7e7 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -118,6 +118,7 @@ int  relative_pid = 1;              /* process id starting 
at 1 */
 /* global options */
 struct global global = {
        .nbproc = 1,
+       .grace = TICK_ETERNITY,
        .req_count = 0,
        .logsrvs = LIST_HEAD_INIT(global.logsrvs),
        .maxzlibmem = 0,
@@ -158,6 +159,7 @@ struct global global = {
 
 int stopping;  /* non zero means stopping in progress */
 int jobs = 0;   /* number of active jobs (conns, listeners, active tasks, ...) 
*/
+int grace = TICK_ETERNITY;
 
 /* Here we store informations about the pids of the processes we may pause
  * or kill. We will send them a signal every 10 ms until we can bind to all
@@ -1585,6 +1587,12 @@ static void run_poll_loop()
 
                /* Check if we can expire some tasks */
                next = wake_expired_tasks();
+               if (stopping && (grace != TICK_ETERNITY)) {
+                       if (tick_is_expired(grace, now_ms))
+                               break;
+                       if (next == TICK_ETERNITY || tick_is_expired(next, 
grace))
+                               next = grace;
+               }
 
                /* stop when there's nothing left to do */
                if (jobs == 0)
diff --git a/src/proxy.c b/src/proxy.c
index c76d55d5..024b36fa 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -925,6 +925,8 @@ void soft_stop(void)
        struct peers *prs;
 
        stopping = 1;
+       if (global.grace != TICK_ETERNITY)
+               grace = tick_add(now_ms, global.grace);
        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