Return-Path: Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 95916 invoked by uid 500); 28 Mar 2003 20:40:13 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 95903 invoked from network); 28 Mar 2003 20:40:13 -0000 Message-ID: <3E84B1EC.3050007@Golux.Com> Date: Fri, 28 Mar 2003 15:34:52 -0500 From: Rodent of Unusual Size Organization: The Apache Software Foundation User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2.1) Gecko/20021130 X-Accept-Language: en-us, en MIME-Version: 1.0 To: Apache httpd developers Subject: prototype for worker graceful *shutdown* Content-Type: multipart/mixed; boundary="------------060706000000030803030609" X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. --------------060706000000030803030609 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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!" --------------060706000000030803030609 Content-Type: text/plain; name="graceful-shutdown-worker.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="graceful-shutdown-worker.patch" 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, --------------060706000000030803030609--