2009-05-31

 

Python signal handling

Signals are one of the most under estimated tools on POSIX systems. Windows is supposed to also handle (some) signals, but I've never used it and don't plan to either. These notes are therefor based on Linux and similar behaving systems.

I used signal processing a lot in Perl coding but since I'm still learning Python I thought it might be a good idea to check it out. As it turns out, it's extremely easy in Python.

For this sample app I wanted to know how easy it would be to tell the app the re-read it's config. The app doesn't really do anything useful but it may perhaps be used for a skeleton of some sorts. Here goes:

#!/usr/bin/python

import sys
import signal
import time

sleeptime = 5.0 # Every how many seconds do we need to perform hosekeeping
house_tracker = 0 # Track the last time we did housekeeping

def SigUSR1Handler(signum, frame):
global house_tracker
house_tracker = time.time() # Reset the timer of the last house keeping
print "Reacting on USR1 signal (signal 10)"
HouseKeepingRoutines()
return

def ReadConfig():
print str( time.time() ) + "\tRead Config"
return

def Housekeeping( timestamp, interval=10 ):
global house_tracker # Last time we did house cleaning
if ( timestamp - house_tracker ) > interval:
print str( timestamp ) + " - Housekeeping timer reached. Running house cleaning routines"
house_tracker = timestamp
HouseKeepingRoutines()
return

def HouseKeepingRoutines():
# Put all the housekeeping functions here
ReadConfig( )
return

signal.signal( signal.SIGUSR1, SigUSR1Handler )

# Set initial timers
start_time = time.time()
previous_time = start_time
abs_starttime = start_time
while(1):
time_now = time.time()
if ( time_now - previous_time ) > sleeptime:
previous_time = time_now
running_time = time_now - abs_starttime
print "Uptime: '" + str( running_time ) + "' seconds"
Housekeeping( time_now )
time.sleep( 1 )


It may look complicated at first glance but it's really not. The app behaves like a "server" that needs to do some house keeping from time to time. When it starts up all timers start fresh and the house keeping routines are called immediately. Part of the house keeping is to read (or re-read) the configuration file - which in this sample just prints a message to STDOUT.

But, if you run the app and you get it's process ID, you can send it a SIGUSR1 signal and you will see from the output it re-read it's config. To issue the command:

$ kill -10 23456


That's assuming of course your app is running with process id 23456.

"But why" you may wonder?

Well, for one thing you can tweak the configuration parameters and in stead of a restart you can tell your app just to re-read and apply the new configuration parameters. A good example could be that you need to change DB servers to do maintenance on your primary. With this method you could force your app to drop all current DB connections and re-establish the connection with the new parameters. Of course you will have to write some extra code - but I'm sure you understand the concept.

Being able to make changes in a production environment without customer impact is sort of a holy grail for most IT shops. This gets you one step closer.

Enjoy!

Labels: , ,


Comments:
This was definitely useful, thanks :)
 
My implementation is causing the code to exit when i issue a SIGUSR1.

In api http://docs.python.org/library/os.html it states, 'Any other value for sig will cause the process to be unconditionally killed by the TerminateProcess API, and the exit code will be set to sig'. I'm using a linux server. I am either misunderstanding or implementing wrong. Any clue on what I maybe doing wrong causing my process to exit instead of just executing handler and then continuing on. The handler is be executed correctly, just doesn't continue program execution.

Thanks.
 
Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?