On 09/11/2009 04:26 PM, Jonathan Swartz wrote: > I'm thinking about an improved solution to recognizing module changes in > a running server, without restarting the server.
This thread is quite old, but it inspired me to implement a similar strategy for dealing with module changes under mod_perl. In my case, I was only really interested in restarting the server when modules under a certain namespace changed (all of my app's modules are under a single namespace, "My" for example). My solution involved forking off a watcher process when the server starts up. This watcher processes uses File::ChangeNotify to watch for changes in the given modules. A nice benefit of using ::ChangeNotify, is if you are on Linux, and have the Linux::Inotify2 modules installed, then this happens with no cpu overhead, and changes are seen almost instantaneous. Once a change happens, my watcher processes detaches from apache, and reloads it (retrying some configured number of times in case there is a syntax error on the first change). To do this, I created a module My::Apache2::Reload. I register the handler in httpd.conf as: PerlPostConfigHandler My::Apache2::Reload When apache starts up, it immediately restarts itself, so my handler has to arrange to only start the watcher subprocess one time. I do this on the second restart like this: > sub handler : method { > return Apache2::Const::OK unless Apache2::ServerUtil::restart_count() == > 2; > > start_watcher(); > > return Apache2::Const::OK; > } start_watcher is implemented as follows: > sub start_watcher { > unless (fork) { # child > require File::ChangeNotify; > > my $module_dir = '/path/to/my/modules'; > my $config_dir = '/path/to/my/configs'; > > my $watcher = File::ChangeNotify->instantiate_watcher( > directories => [$module_dir, $config_dir], > filter => qr/\.(?:pm|conf|yml)$/); > > while (my @events = $watcher->wait_for_events) { > my @event_types = map { $_->type } @events; > if (any(@event_types) eq 'modify') { > restart_apache(); > } > } > } > } And restart_apache() is called when something that is watched changes: > sub restart_apache { > disconnect_from_apache(); > > require IPC::System::Simple; > > for my $attempt (1 .. $MaxRestartTries) { > if ($attempt > 1) { > sleep $RestartDelay; > } > > eval { > IPC::System::Simple::system('apache restart command'); > CORE::exit(0); > }; > } > > # give up. > CORE::exit(0); > } The disconnect_from_apache() is necessary because the watcher gets killed off if you do not close all open filehandles in the child when the restart is attempted. Also we need to detach from the apache process group. This is done as follows: > sub disconnect_from_apache { > POSIX::setsid(); > > # close all open fds. > my $max_fds = POSIX::sysconf(&POSIX::_SC_OPEN_MAX) // 64; > > for my $fd (0 .. $max_fds) { > POSIX::close($fd); > } > } And thats it. This has worked wonderfully for me. Apache notices changes in real time, and restarts happen quickly when developing. If there is interest in a module like this, let me know and I will package it up and put it on CPAN (obviously I wouldn't use the name Apache2::Reload as that is taken already :)). Regards, Michael Schout