mirror of
https://github.com/haproxy/haproxy.git
synced 2026-02-18 18:19:39 -05:00
MEDIUM: global: add a 'hard-stop-after' option to cap the soft-stop time
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.
This commit is contained in:
parent
1a943c48fb
commit
203ec5a2b5
4 changed files with 88 additions and 1 deletions
|
|
@ -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".
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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 killed; /* non zero means a hard-stop is triggered */
|
||||
extern char hostname[MAX_HOSTNAME_LEN];
|
||||
extern char localpeer[MAX_HOSTNAME_LEN];
|
||||
extern struct list global_listener_queue; /* list of the temporarily limited listeners */
|
||||
|
|
@ -194,6 +196,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)());
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
@ -157,6 +158,7 @@ struct global global = {
|
|||
/*********************************************************************/
|
||||
|
||||
int stopping; /* non zero means stopping in progress */
|
||||
int killed; /* non zero means a hard-stop is triggered */
|
||||
int jobs = 0; /* number of active jobs (conns, listeners, active tasks, ...) */
|
||||
|
||||
/* Here we store informations about the pids of the processes we may pause
|
||||
|
|
@ -593,6 +595,7 @@ static void init(int argc, char **argv)
|
|||
*/
|
||||
|
||||
totalconn = actconn = maxfd = listeners = stopping = 0;
|
||||
killed = 0;
|
||||
|
||||
|
||||
#ifdef HAPROXY_MEMMAX
|
||||
|
|
@ -1225,7 +1228,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;
|
||||
|
|
|
|||
64
src/proxy.c
64
src/proxy.c
|
|
@ -914,6 +914,58 @@ struct task *manage_proxy(struct task *t)
|
|||
}
|
||||
|
||||
|
||||
static int proxy_parse_hard_stop_after(char **args, int section_type, struct proxy *curpx,
|
||||
struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
const char *res;
|
||||
|
||||
if (!*args[1]) {
|
||||
memprintf(err, "'%s' expects <time> as argument.\n", args[0]);
|
||||
return -1;
|
||||
}
|
||||
res = parse_time_err(args[1], &global.hard_stop_after, TIME_UNIT_MS);
|
||||
if (res) {
|
||||
memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct task *hard_stop(struct task *t)
|
||||
{
|
||||
struct proxy *p;
|
||||
struct stream *s;
|
||||
|
||||
if (killed) {
|
||||
Warning("Some tasks resisted to hard-stop, exiting now.\n");
|
||||
send_log(NULL, LOG_WARNING, "Some tasks resisted to hard-stop, exiting now.\n");
|
||||
/* Do some cleanup and explicitely quit */
|
||||
deinit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
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) && (p->feconn > 0)) {
|
||||
Warning("Proxy %s hard-stopped (%d remaining conns will be closed).\n",
|
||||
p->id, p->feconn);
|
||||
send_log(p, LOG_WARNING, "Proxy %s hard-stopped (%d remaining conns will be closed).\n",
|
||||
p->id, p->feconn);
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
list_for_each_entry(s, &streams, list) {
|
||||
stream_shutdown(s, SF_ERR_KILLED);
|
||||
}
|
||||
|
||||
killed = 1;
|
||||
t->expire = tick_add(now_ms, MS_TO_TICKS(1000));
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 +975,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) {
|
||||
|
|
@ -1215,6 +1278,7 @@ int stream_set_backend(struct stream *s, struct proxy *be)
|
|||
}
|
||||
|
||||
static struct cfg_kw_list cfg_kws = {ILH, {
|
||||
{ CFG_GLOBAL, "hard-stop-after", proxy_parse_hard_stop_after },
|
||||
{ CFG_LISTEN, "timeout", proxy_parse_timeout },
|
||||
{ CFG_LISTEN, "clitimeout", proxy_parse_timeout },
|
||||
{ CFG_LISTEN, "contimeout", proxy_parse_timeout },
|
||||
|
|
|
|||
Loading…
Reference in a new issue