[mod_python] Need help with server register_cleanup

Graham Dumpleton grahamd at dscpl.com.au
Wed Jan 11 17:13:42 EST 2006


jelle wrote ..
> I'm trying to use mp_server register_cleanup to dump some collected 
> runtime stats but need a more explicit code example.
> 
> As I understand it, server.register_cleanup function is called when the
> apache child process is terminated. Currently I have an apache directive
> set as MaxRequestsPerChild 10 to test that functionality.
> 
> Questions:
> 
> I'm using mp_servlets, should the register_cleanup call be in the mainline
> of a commonly imported file or should it be placed in a commonly called
> function or either way?
> 
> What is the appropriate import statement?
> 
> Does the callable function expect and parameters?
> 
> What is the complete call look like?

In mod_python 2.7 and 3.1, to register a cleanup handler to be
executed when the server is shutdown, a call needs to be made to:

  req.server.register_cleanup()

Because the function is accessed via the request object, the call can only
be made from with the context of an executing handler where there
request object is actually available. Thus:

  def cleanup(data):
    ...

  def handler(req):
    req.server.register_cleanup(req,cleanup)
    ...

The problem here is that you don't actually want the function to be called
everytime the request handler is called. Thus you need to have a flag to
indicate whether you have already called it. Presuming you are using a
non threaded Apache MPM, you would thus write:

  flag = False

  def handler(req):
     if not flag:
       flag = True
       req.server.register_cleanup(req,cleanup)

If you are using a multithreaded MPM, access to that flag and the call to
register the cleanup function is going to have to be thread protected so
that the initialisation isn't done by two different threads at the same time.

The next problem you need to contend with is that if module reloading
if allowed on this module it will result in registration happening every time
the module is reloaded. Thus, you actually need to put the code in a
separate module which is not the subject of module reloading. Ie., it
should be a distinct module on your PYTHONPATH imported using 'import'
and not in the document tree.

  # myinitmodule.py

  try:
    import threading
  except:
    import dummy_threading as threading

  lock = threading.Lock()

  flag = False
  
  def cleanup(data):
    ...

  def register_cleanup(req):
    lock.acquire()
    if not flag:
      flag = True
      req.server.register_cleanup(req,cleanup)
    lock.release()

  # handler.py

  import myinitmodule

  def handler(req):
    myinitmodule.register_cleanup(req)
    ...

Having said that, it is not gauranteed that the cleanup handler will
actually be called. It will only be called when there is a clean shutdown.
If the Apache child process gets hung on shutdown and the parent
process has to explicitly kill it, the cleanup handler may not be called.
This is compounded by the currently known issue of:

  http://issues.apache.org/jira/browse/MODPYTHON-109

The above is the portable way of doing it for different versions of
mod_python. In mod_python 3.2, you are also able to access the
function for registering a cleanup function direct from the 'apache'
module. This call does not require the request object to be available.
Thus in mod_python 3.2, you can actually say:

  # myinitmodule.py

  from mod_python import apache

  try:
    import threading
  except:
    import dummy_threading as threading

  lock = threading.Lock()

  flag = False
  
  def cleanup(data):
    ...

  def register_cleanup():
    lock.acquire()
    if not flag:
      flag = True
      apache.register_cleanup(cleanup)
    lock.release()

  # handler.py

  import myinitmodule
  myinitmodule.register_cleanup()

  def handler(req):
    ...

Because in mod_python 3.2 you can do this, you could even use the
PythonImport directive to import a module which does the registration
and thus avoid having to do it in some handler module.

Graham


More information about the Mod_python mailing list