[mod_python] Application session

Graham Dumpleton grahamd at dscpl.com.au
Sun Jan 7 00:46:13 EST 2007


Have forwarded this back to the list. Please keep followups there.

Depending on what you are doing, you might want to look at memcached
for Python as a way of sharing memory between Apache child processes.
Alternatively, look at XML-RPC as a way to connect to a long lived back
end process which contains the true application.

For even more complicated systems, can also suggest messaging system
based solutions for communicating with a back end system. These have
the benefit of not requiring a separate socket connection for each  
request
like XML-RPC does. Down the track, if interested in these, let me know.

Graham

On 07/01/2007, at 1:49 PM, Michael Rasmussen wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Graham,
>
> I might have solve my problems. Your article helped a lot.
> Read my solution a clarification of my problem below.
>
> On Sat, 6 Jan 2007 11:38:14 +1100
> Graham Dumpleton <grahamd at dscpl.com.au> wrote:
>
>>
>> You might then perhaps explain better what you are talking about.
>>
>> In short, any module that is imported within the context of a Python
>> interpreter instance is usable by any handler executing within that
>> Python interpreter instance in that process. This is totally
>> unrelated to
>> user sessions created as a result of some form based/login mechanism.
>>
>> What isn't clear is whether when you say 'sessions' you are talking
>> about user sessions or merely concurrent executing request handlers.
>>
> The picture:
>
> I have an application which provides admin users the ability to add
> extensions into the runtime. These extensions must be available to all
> users as soon as they are instantiated without the users needs for
> restarting their sessions. The extensions must also be persistent in
> the runtime until either the application/apache is restarted or they
> deactivated by the admin users. Had the application been programmed in
> Java - JSP/Servlets, such extensions would have be stored in the
> application session: <jsp:useBean id="applicationBean"
> class="some.Bean" scope="application" />. This means that for any user
> session currently and later on can access the bean and its members. In
> Java/JSP you operate with four different kinds of scope: page,  
> request,
> session and application. the first three are all related to the same
> user session in the said application while the last one is related to
> the application instance and the by nature related to all users of the
> application. Studying your article proved to me that mod_python does
> not provide application scope directly?
>
> My application is running in apache under GNU/Linux so it is  
> restricted
> to the problems described in your article - prefork and worker. By the
> way does this problem also apply to MPM worker?
>
> What I have found out is this:
> I thought I could create a class implementing the singleton pattern  
> and
> store an instance of the class to the request object but even if a
> directory/virtual host only designates one python handler one cannot
> rely on that all instances will share the same python
> runtime/pythonHandler due to apache's forking nature so this was a
> dead-end.
>
> So my final solution was to create the said singleton class and in  
> this
> class save private attributes with instance information of the object
> store in dictionaries and then use cPickle to store and load the
> object's state. Since I cannot control when an instance of the
> singleton class is unloaded from the session I was forced to save the
> state of the object every time the object's state change.
>
> If anybody is interested you can find my solution below
>
> """
> IPCop Module Loader.
>
> This module is licensed under GPL and is part of the UI to IPCop.
> Read online documentation <http://www.ipcop.org>.
>
> Copyright: 2006, Michael Rasmussen <mir at datanom.net>
>
> Last maintainer: 2006-08-21 18:57 +0200 Michael Rasmussen
> <mir at datanom.net>
>
> Previous maintainers:
>
> If you find any bugs or have any comments please send an email to
> Michael Rasmussen <mir at datanom.net>
> """
>
> VERSION = "0.1"
>
> import os, sys, new, cPickle, anydbm, tempfile, ModuleImporter
>
> class ModuleLoaderException(Exception):
>     def __init__(self, msg):
>         self.value = msg
>
>     def __str__(self):
>         return repr(self.value)
>
> class ModuleLoader:
>     """
>         Available modules contains reference to
>         registered modules.
>         Key: ModuleId
>         Item: Reference to a module
>     """
>
>     __instance = None
>
>     def __init__(self):
>         if ModuleLoader.__instance is None :
>             ModuleLoader.__instance = ModuleLoader.__singleton()
>         self.__dict__['_ModuleLoader__instance'] =
> ModuleLoader.__instance def __getattr__(self, attr):
>         return getattr(self.__instance, attr)
>
>     def __setattr__(self, attr, value):
>         return setattr(self.__instance, attr, value)
>
>     class __singleton:
>
>         def __init__(self):
>             dbmIn = anydbm.open(tempfile.gettempdir() +
> 		"/ipcop_modules.dbm", "c")
> 	    try:
>                 self.__availableModules =
>                     cPickle.loads(dbmIn["availableModules"])
>             except KeyError:
>                 self.__availableModules = {}
>             try:
>                 self.__activeModules =
>                     cPickle.loads(dbmIn["activeModules"])
>             except KeyError:
>                 self.__activeModules = {}
>             dbmIn.close()
>
>         def getModulesList(self):
>             try:
>                 return self.__availableModules
>             except AttributeError:
>                 return {}
>
>         def setModulesList(self, list):
>             self.__availableModules = list
>             dbmOut = anydbm.open(tempfile.gettempdir() +
>                 "/ipcop_modules.dbm", "c")
>             dbmOut["availableModules"] =
>                 cPickle.dumps(self.getModulesList(), 1)
>             dbmOut.close()
>
>         def setAvailableModule(self, name, desc):
>             self.__availableModules[name] = desc
>             dbmOut = anydbm.open(tempfile.gettempdir() +
>                 "/ipcop_modules.dbm", "c")
>             dbmOut["availableModules"] =
>                 cPickle.dumps(self.getModulesList(), 1)
>             dbmOut.close()
>
>         def register(self, module, path = None):
>             try:
>                 if path != None:
>                     if (path.find(".") != -1):
>                         raise ModuleLoaderException("Illegal character
> in path")
>                     if (not path.startswith("/")):
>                         if (os.getcwd() != '/'):
>                             path = os.getcwd() + "/" + path
>                         else:
>                             path = "/" + path
>                     if (path in sys.path):
>                         pass
>                     else:
>                         sys.path.append(path)
>                 mod = ModuleImporter.get_mod(module)
>                 try:
>                     modules = getattr(mod,"__all__")
>                     for m in modules:
>                         self.register(module + "." + m)
>                 except AttributeError:
>                     lastDot = module.rfind(u".")
>                     module = module[lastDot + 1:]
>                     self.setAvailableModule(module, getattr(mod,
> "__name__"))
>                     ModuleImporter.del_mod(getattr(mod, "__name__"))
>             except Exception, ex:
>                 raise ModuleLoaderException("Loading module: %s" % ex)
>
>         def unregister(self, module):
>             """ unregister """
>             t = self.getModulesList()
>             del t[module]
>             self.setModulesList(t)
>             dbmOut = anydbm.open(tempfile.gettempdir() +
> "/ipcop_modules.dbm", "c")
>             dbmOut["availableModules"] =
> cPickle.dumps(self.getModulesList(), 1)
>             dbmOut.close()
>             ModuleImporter.del_mod(getattr(module, "__name__"))
>
> - --
> Hilsen/Regards
> Michael Rasmussen
>
> Get my public GnuPG keys:
> michael <at> rasmussen <dot> cc
> http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xD3C9A00E
> mir <at> datanom <dot> net
> http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE501F51C
> mir <at> miras <dot> org
> http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE3E80917
> - --------------------------------------------------------------
> It's all in the mind, ya know.
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (GNU/Linux)
>
> iD8DBQFFoF+/VErYVePoCRcRAtV3AKCiqlVRGu+l8KVno28zxC/6tkl4cgCfQU4L
> 5Rb3VaXrFtWehT7S5Al+2nk=
> =io+9
> -----END PGP SIGNATURE-----


More information about the Mod_python mailing list