the attached patch, based on one bill started, presses SIGINT
into service as a 'graceful shutdown' signal. (alternative
suggestions highly welcomed.) if the config directive
GracefulShutdownTimeout is set (default is 10), when the
server is sent a SIGINT it will go into shutdown mode but
not actually go all the way down until that many seconds have
passed. SIGTERM works normally for a graceless shutdown.
i'd rather not re-add another signal, but oh well.. the
alternative is to set GracefulShutdownTimeout to zero as
the default (either in .c or .conf) to keep the current
behaviour -- but then to take advantage of it you'd need to
edit the .conf file, do a restart, and then do a shutdown.
bleah.
expansion to other mpms and command-line interface waiting
for non-vetoed acceptance of this proof-of-concept.
--
#ken P-)}
Ken Coar, Sanagendamgagwedweinini http://Golux.Com/coar/
Author, developer, opinionist http://Apache-Server.Com/
"Millennium hand and shrimp!"
Index: configure.in
===================================================================
RCS file: /home/cvs/httpd-2.0/configure.in,v
retrieving revision 1.246
diff -u -r1.246 configure.in
--- configure.in 8 Mar 2003 13:54:41 -0000 1.246
+++ configure.in 28 Mar 2003 19:30:52 -0000
@@ -164,6 +164,7 @@
APACHE_SUBST(LTCFLAGS)
AP_SIG_GRACEFUL=USR1
+AP_SIG_GRACEFUL_STOP=INT
case $host in
*-apple-aux3*)
@@ -477,11 +478,14 @@
AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL, SIG$AP_SIG_GRACEFUL, [Signal used to gracefully
restart])
AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_STRING, "SIG$AP_SIG_GRACEFUL", [Signal used to
gracefully restart (as a quoted string)])
AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_SHORT, $AP_SIG_GRACEFUL, [Signal used to
gracefully restart (without SIG prefix)])
+AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_STOP, SIG$AP_SIG_GRACEFUL_STOP, [Signal used to
gracefully shut down])
AP_SIG_GRACEFUL_SHORT=$AP_SIG_GRACEFUL
AP_SIG_GRACEFUL=SIG$AP_SIG_GRACEFUL_SHORT
+AP_SIG_GRACEFUL_STOP=SIG$AP_SIG_GRACEFUL_STOP
AC_SUBST(AP_SIG_GRACEFUL)
AC_SUBST(AP_SIG_GRACEFUL_STRING)
AC_SUBST(AP_SIG_GRACEFUL_SHORT)
+AC_SUBST(AP_SIG_GRACEFUL_STOP)
dnl check for endianness
if test "$cross_compiling" = "no"; then
Index: server/mpm/worker/worker.c
===================================================================
RCS file: /home/cvs/httpd-2.0/server/mpm/worker/worker.c,v
retrieving revision 1.134
diff -u -r1.134 worker.c
--- server/mpm/worker/worker.c 3 Feb 2003 17:53:26 -0000 1.134
+++ server/mpm/worker/worker.c 28 Mar 2003 19:30:52 -0000
@@ -157,6 +157,7 @@
*/
int ap_threads_per_child = 0; /* Worker threads per child */
+static int graceful_shutdown_timeout = 10;
static int ap_daemons_to_start = 0;
static int min_spare_threads = 0;
static int max_spare_threads = 0;
@@ -436,7 +437,7 @@
* child to force an exit) and so do an exit anyway.
*/
-static void ap_start_shutdown(void)
+static void ap_start_shutdown(int sig)
{
if (shutdown_pending == 1) {
/* Um, is this _probably_ not an error, if the user has
@@ -445,6 +446,13 @@
*/
return;
}
+ /*
+ * If it isn't a graceful shutdown, force it to be graceless by
+ * setting the gracefule timeout to zero.
+ */
+ if (sig != AP_SIG_GRACEFUL_STOP) {
+ graceful_shutdown_timeout = 0;
+ }
shutdown_pending = 1;
}
@@ -462,7 +470,7 @@
static void sig_term(int sig)
{
- ap_start_shutdown();
+ ap_start_shutdown(sig);
}
static void restart(int sig)
@@ -1743,11 +1751,16 @@
server_main_loop(remaining_children_to_start);
if (shutdown_pending) {
- /* Time to gracefully shut down:
- * Kill child processes, tell them to call child_exit, etc...
- * (By "gracefully" we don't mean graceful in the same sense as
- * "apachectl graceful" where we allow old connections to finish.)
+ /* If a graceful_shutdown_timeout is set, allow some time
+ * for in-flight transactions to complete. If they are not
+ * done by the timeout, take them down hard.
+ * Todo: poll to see if the children have shutdown
+ * to save us from waiting the full timeout period.
*/
+ if (graceful_shutdown_timeout != 0) {
+ ap_mpm_pod_killpg(pod, ap_daemons_limit, TRUE);
+ apr_sleep(apr_time_from_sec(graceful_shutdown_timeout));
+ }
ap_mpm_pod_killpg(pod, ap_daemons_limit, FALSE);
ap_reclaim_child_processes(1); /* Start with SIGTERM */
@@ -1937,7 +1950,16 @@
ap_hook_open_logs(worker_open_logs, NULL, aszSucc, APR_HOOK_MIDDLE);
ap_hook_pre_config(worker_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
}
-
+static const char *set_graceful_shutdown(cmd_parms *cmd, void *dummy,
+ const char *arg)
+{
+ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
+ if (err != NULL) {
+ return err;
+ }
+ graceful_shutdown_timeout = atoi(arg);
+ return NULL;
+}
static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy,
const char *arg)
{
@@ -2156,6 +2178,8 @@
static const command_rec worker_cmds[] = {
UNIX_DAEMON_COMMANDS,
LISTEN_COMMANDS,
+AP_INIT_TAKE1("GracefulShutdownTimeout", set_graceful_shutdown, NULL, RSRC_CONF,
+ "Time in seconds to wait for child processes to complete transactions during
shutdown"),
AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF,
"Number of child processes launched at server startup"),
AP_INIT_TAKE1("MinSpareThreads", set_min_spare_threads, NULL, RSRC_CONF,