[mod_python] Udate python modules without restarting Apache

Graham Dumpleton grahamd at dscpl.com.au
Mon Oct 4 18:22:35 EDT 2004


On Oct 04 23:03, berry groenendijk <berry.groenendijk at gmail.com> wrote:
>
> Subject: Re: [mod_python] Udate python modules without restarting Apache
>
> Indeed when I change .py modules in my developement environment, I
> need to restart Apache to get the changes to work. So, I was also
> wondering how to update .py modules on a server at a hosting provider
> that does not allow you to restart the Apache server proces.
> 
> On Mon, 4 Oct 2004 15:06:34 +0100, MJR <pynode at centrum.cz> wrote:
> > Hi,
> > 
> > I'm running mp servlets on Apache server I don't have control over, i.e. I
> > cannot restart it when I change my .py modules imported by my .mps scripts.
> > 
> > I'm just wondering whether there is any hack for this. How people deal with
> > it in a production environment.

I made a few comments on this at the bottom of a recent message, but I'll
try and cover the choices and some of the issues. One of these days I'll
write a proper little discussion piece about module reloading issues and
put it on my web site. There is a lot to it which isn't obvious nor documented
anywhere. ;-)

The basic problem is that when you use the "import" statement in Python to
bring a module into code executing under Python, if you later what to change
and reinstall that module, about the only thing you can do is to restart Apache.
In an environment where you don't have control over Apache to do that, that
becomes a problem.

The first and quickest thing you can do is a mega hack and may not be a
good thing to do in a production environment, but if you are desperate it
can be a life saver.

What you can do here is to explicitly delete the modules out of sys.modules
and touch all handler code files which import the modules so that they will
get reloaded by mod_python the next time they are accessed. You will need
to ensure that PythonAutoReload is On.

To do this, create a separate directory somewhere which is setup for using
mod_python.publisher. Ie.,

  SetHandler python-program
  PythonHandler mod_python.publisher

In that directory create a file "purge.py" which deletes all the modules
you need to delete. Ie., contains something like:

  def doit():
    try: del sys.modules["HTMLTemplate"]
    except: pass

    try: del sys.modules["vampire"]
    except: pass

    for key in sys.modules.keys():
      if string.find(key,"vampire.") == 0:
        del sys.modules[key]

  modules = sys.modules.keys()
  modules.sort()

  return modules

Then access the page "purge/doit". Note that if Apache is running in prefork
mode, you will have to keep reloading the page until you think you have
managed to invoked the code in all separate forked Apache processes.
Not sure about threaded servers or where separate interpreters are used.

As I said it is a mega hack, but if you are desperate... Be warned that It is
entirely feasible that it may cause everything to stuff up completely. Thus,
if you are talking high volume production site where the pages are being
accessed constantly and you are not the only one with mod_python hosted
code then don't do it. If it is a production web server where your mod_python
code is the only such code and hardly anyone uses it anyway, can be used
with caution.

Note that I would only suggest this be done for code modules which are
specifically intended to be imported as part of your mod_python application.
Ie., don't do it for modules which are used by other mod_python applications.
That way you limit damage to your own stuff and you only have yourself
to blame for the problems. :-)

Moving towards a proper solution, simply don't use "import" at all for your
common code modules in your mod_python application. To achieve this,
you can use mod_python.apache.import_module() method. Thus, instead
of using:

  from mymodules import mymodules

use:

  from mod_python import apache
  module1 = apache.import_module("mymodules.module1")

There are a few issues with the import_module() method though that you
have to be mindful of and you may still have to poke at things a bit to get
it to work.

The first is that even though "mymodules.module1" will now be reloaded,
it will only be done so if this loading of the module is down from inside a
method defined within the content handler and called as part of request
handling.

That is, if you stick this at global scope in your content handler code file,
it will only be called once when the content handler code file is imported.
If you still want it at global scope, you would also need to touch the content
handler code file so that its modification time is updated. That way the
content handler will be reloaded and the module reloaded as well.

Note that the import_module() method will though only reload a module
when the modification time is newer than what it was before. This means
that if you restored an old copy of a module such that its modification time
was actually older, it will not reload. You will need to touch the file to make
its modification time newer.

The next issue is that this is probably useless if "module1" uses "import" to
bring in "modules2" from your "mymodules" directory. That is, any change
to "modules2" will not be reloaded. Thus, any imports amongst your own
modules should also use "import_module()". To find "module2" in this case,
I am not sure if "module1" would need to load it as "mymodules.module2"
or just "module2". I would suggest that "mymodules.module2" would be
preferred and may actually be necessary.

Now if "module2" was imported at global scope in "module1", you end up
with the same problem that even if it is modified it will not be reloaded.
You basically end up with a whole chaining problem and if you do this you
end up still having to touch higher up files in the chain to update the
modification times so that they are reloaded.

So, although extra poking is required in the way of touching some files to
update modification times, you can at least trick mod_python into reloading
things without restarting Apache.

Now, some of the above is based on theory only, so if I am wrong, people
please correct me.

BTW, if you want to see my attempt at an alternate module loading system
which tries to deal with the chaining issue. I have developed a package
for mod_python called Vampire. When used properly, you can change
"module2" and without having to touch the timestamp on any files,
"module1" and any content handlers which use "module1" or "module2"
would be automatically reloaded the next time they are accessed.
Obviously there will be a performance hit with the extra checking, but
if you want maximum flexibility in the way of making changes...

Version 1.0 of Vampire, lacking any documentation on the module loading
system, can be found at:

  http://www.dscpl.com.au/projects/vampire

I have the code for Vampire 1.1 ready, which adds more nice features, but
am still fiddling with the slightly better documentation and examples. I have
not tried integrating it with mpservlets yet, but 1.1 does show at a high level
how it can be used in conjunction with psp. Note that it doesn't try and address
some of the chaining issues of making changes in psp code itself though.

--
Graham Dumpleton (grahamd at dscpl.com.au)


More information about the Mod_python mailing list