[TransWarp] Multiapp multithreaded server and configurable services
rk at dat.cz
Fri Jun 20 11:11:04 EDT 2003
with the help of PEAK and Twisted I want to build threaded application
server that will be able to serve multiple applications. Every
application is composed from PEAK components and hierarchy typicaly
looks like this:
| +- dm11
| +- svc111
| +- svc112
Application instances reside in pools. Number of instances is
configurable according to assumed application load. app_root1 typicaly
holds database connection or any other resource. Server has
some number of worker threads that get application instance from pool
and do its work upon client request. App instance is returned then
back into pool.
Applications are very simmilar and components svc1, dm21, svc22, ...
will be often components from library. Every component will be configurable
with zconfig or some custom XML format (not decided yet). This configuration
must be able to address specific component on specific path in specific
application. I must be able to say, that component '/svc1/dm11/svc111'
of application 'app1' has value 'vvv' of property 'ppp' or '/svc2/'
has subservice 'dm22' of some type. Subservices of some specific service
are defined staticaly in python module (via bindService) or can be specified
in configuration: "service '/svc2' has subservice 'dm21' of class
What is the problem?
Assume that 'app2:/dm1' and 'app1:/svc1/dm11' are the same library
components lib.contact:ContactDM. There is undesirable to create child
components inherited from ContactDM only for purpose of modifying some
parameters (parameters are configured in custom config as possible).
But this ContactDM can have some classAttr (typicaly cache)
that canot be shared on 'app2:/dm1' and 'app1:/svc1/dm11' occurences
of ContactDM class. Obviously this components will be working on different
databases or tables and cannot share cache.
I have started to code some binding utilities that could solve my problem
but I want to ensure that PEAK doesn't provide some solution before doing
useless work. My solution looks like this and I will be able to post
more details here soon:
class bindService(binding.Once) :
"""Adapts service parameter to IServiceFactory and creates
its copy upon first request. Parameter can be directly subclass
of Service or subclass of IServiceFactory. If it is interface,
class that implements it can be configured. Information that
lib.contact:ContactDM implements IContactFactory is configurable
per application and specific component occurence (path).
serviceAttrs are replaced with classAttrs in copy.
classAttrs are kept intact.
Additionaly it loads parameters from appropriate part of
custom configuration into created IService instance.
Configuration is obtained from ServiceRoot that must
be known during calling bindService.computeValue().
def __init__(self, service, **kw) :
self.service = service
class Service (binding.Component) :
"""Parent of all service classes. It has methods for allocating
persistent resources, doing authorization and subservices lookup.
class serviceAttr (object) :
class ServiceRoot (Service, ConfigurationRoot) :
"""Eats custom configuration and provides it to subservices.
More information about the PEAK