Tags:
Apache1Add my vote for this tag Linux1Add my vote for this tag Mod Perl1Add my vote for this tag Perl1Add my vote for this tag Scripts1Add my vote for this tag System Administration1Add my vote for this tag create new tag
, view all tags

Automatically Reload Apache When Files Change - For mod_perl

I have been getting very annoyed with needing to reload / restart Apache every time that I make a change to a module or a script when developing a new mod_perl project.

This has led me to create a simple perl script to monitor selected directories for changes and reload Apache.

The script could really be used to do just about anything when a given directory changes (by just changing the apache reload command path variable), but this is the use that I made it for, and the log file messages would need to be changed.

You can easily configure the frequency that the script checks for changes and the directories / files that you want to monitor are stored in a configuration file ( just a list of directories ). You can change the paths of everything pretty easily.

The script just runs a quick stat on all of the files in the directories and grabs an MD5 sum and compares the result to the previous result.

No cronjobs needed as the script forks into the background. I start the script at server startup through rc.local on my system.

This is suitable for a production system and won't reduce performance of your application since the additional overhead of Apache::Reload / Apache2::Reload isn't introduced.

Here is the script, if you want to use it.

#!/usr/bin/perl
##################################################################################################################
#
# monitor_http_docs.pl
#
# Author:
#
#       Jeffrey Weitz
#       jeffdoubleyou@gmail.com
#       jeffdoubleyou.com
#
# Synopsis:
#
#       Monitor configured directories for changes and reload Apache ( or run other commands )
#       on modification.
#
#       This is useful mostly for mod_perl applications when you make a change to a module or cgi script and don't
#       want to have to manually reload Apache every time you change something and don't want to introduce the
#       overhead involved with Apache::Reload / Apache2::Reload .
#
####################################################################################################################
use strict;

# Don't print output to the console!
open STDOUT, '>/dev/null';

my $pid;
my $md5;
my $last_md5;
my $files;
my $pid_file = "/var/run/monitor_http_docs";
my $log_file = "/var/log/monitor_http_docs.log";
my $frequency = 2;
my $conf_file = "/etc/monitor_http_docs.conf";
my $apache_command = '/etc/init.d/httpd reload';
my $md5sum_path = '/usr/bin/md5sum';

# This should remove the PID file should we be shutdown unexpectedly
$SIG{'INT'} = 'CLEANUP';

# If the PID file exists, let's see what process should be running
if( -e $pid_file )
{
        open(PID, "$pid_file") || die("Could not open pid file - $!");
        $pid = <PID>;
        close(PID);
}

# If there is a PID and it doesn't match the current process, let's try to kill it:
if($pid && $pid != $$)
{
        open(LOG, ">>$log_file") || die("Unable to open log file ( $log_file ) - $!\n");
        print LOG localtime() . " Trying to kill existing process [ $pid ] ";
        if(kill 15, $pid)
        {
              print LOG " [ OK ]\n";
        }
        else
        {
              print LOG " [ FAILED ] - $!\n";
              die("Unable to stop already running $0 - $!\n");
        }
}

# Fork into the background
my $child = fork();

# If we have spawned a child:
if($child > 0)
{
        open(LOG, ">>$log_file");
        print LOG localtime() . " Running as PID $child\n";
        close(LOG);

        # Write PID file
        open(PID, ">$pid_file") || die("Unable to create PID file - $!");
        print PID $child;
        close(PID);

        # Get out now
        exit;
}

# Get directories to watch:
open(CONF, "$conf_file") || die("Unable to read config file ( $conf_file ) - $!\n");
my @confs = <CONF>;
close(CONF);

# Add directories to the list
open(LOG, ">>$log_file");
foreach my $watch (@confs)
{
        chomp($watch);
        $files .= "$watch/* ";
        print LOG localtime() . " Adding $watch to watched directories\n";
}
close(LOG);

# Run forever - checking at $frequency second intervals
while(sleep $frequency)
{
        $md5 = `stat -t -c%Y-%Z $files | $md5sum_path`;
        if($last_md5 && $md5 ne $last_md5)
        {
              open(LOG, ">>$log_file");
              print LOG localtime() . " Found a change to monitored directories - reconfiguring apache and checking again in $frequency seconds\n";
              if(system($apache_command) == 0)
              {
                print LOG localtime() . " Reconfiguring apache completed\n";
              }
              else
              {
                print LOG localtime() . " Reconfiguration FAILED!\n";
              }
              close(LOG);
        }

        $last_md5 = $md5;
}

# Cleanup on kill
sub CLEANUP {
        unlink $pid_file || die("Unable to remove PID file - $!\n");
        exit(1);
}

-- JeffreyWeitz - 2010-05-02

 

  • I don't know why I didn't make a logging sub. -- JeffreyWeitz - 05 May 2010
Topic revision: r2 - 2010-05-05 - 02:47:42 - JeffreyWeitz

notify Notifications
feed RSS Feed
statistics Statistics

newtopic Create New Topic

 

Search Site:

Copyright © by Jeffrey Weitz - AKA jeffdoubleyou - AKA Jeff Weitz. All material on this site is the property of the contributing authors.