Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Web Site Process Bus

A Bus object is used to contain and manage site-wide behavior: daemonization, HTTP server start/stop, process reload, signal handling, drop privileges, PID file management, logging for all of these, and many more.

In addition, a Bus object provides a place for each web framework or application to register code that runs in response to site-wide events (like process start and stop), or which controls or otherwise interacts with the site-wide components mentioned above. For example, a framework which uses file-based templates would add known template filenames to an autoreload component.

The Bus object is flexible enough to be useful in a variety of invocation scenarios:

  1. The deployer starts a site from the command line via a framework-neutral deployment script; applications from multiple frameworks are mixed in a single site. Command-line arguments and configuration files are used to define site-wide components such as the HTTP server, WSGI component graph, autoreload behavior, signal handling, etc.
  2. The deployer starts a site via some other process, such as Apache; applications from multiple frameworks are mixed in a single site. Autoreload and signal handling (from Python at least) are disabled.
  3. The deployer starts a site via a framework-specific mechanism; for example, when running tests, exploring tutorials, or deploying single applications from a single framework. The framework controls which site-wide components are enabled as it sees fit.

The Bus object in CherryPy uses topic-based publish-subscribe messaging to accomplish all this. A few topic channels are built in ('start', 'stop', 'exit', 'log(msg)', and 'graceful'). Frameworks and site containers are free to define their own. If a message is sent to a channel that has not been defined or has no listeners, there is no effect.

In general, there should only ever be a single Bus object per process. Frameworks and site containers share a single Bus object by publishing messages and subscribing listeners.

The Bus object works as a finite state machine which models the current state of the process. Bus methods move it from one state to another; those methods then publish to subscribed listeners on the channel for the method. See wiki:WSPBSpec for more details.

Writing deployment scripts

Using a bus object encourages you to write your startup and shutdown code as objects in a reusable fashion. For example, given a typical deployment script like this:

db = None

if __name__ == '__main__':
    config = get_config()
    
    sys.stderr.write("Opening database connection: %s." % self.connstr)
    global db
    db = dbapi.open(config['connstr'])
    try:
        cherrypy.engine.start()
        cherrypy.engine.block()
    finally:
        sys.stderr.write("Closing database connection: %s." % self.connstr)
        db.close()

...using a Bus object encourages you to move that code into an object:

class Persistence(plugins.SimplePlugin):
    """Manages the database."""
    
    def __init__(self, bus, connstr):
        self.bus = bus
        self.connstr = connstr
        self.db = None
    
    def start(self):
        self.bus.log("Opening database connection: %s." % self.connstr)
        self.db = dbapi.open(connstr)
    start.priority = 20
    
    def stop(self):
        self.bus.log("Closing database connection: %s." % self.connstr)
        self.db.close()
        self.db = None


if __name__ == '__main__':
    config = get_config()
    p = Persistence(cherrypy.engine, config['connstr'])
    p.subscribe()
    cherrypy.engine.start()
    cherrypy.engine.block()

Then you can "import p.db" in the rest of your code and run with it (although, because CherryPy is multithreaded, you'll probably want to make sure your 'db' object is actually a threadsafe connection pool).

The first approach works well enough when you're only deploying simple sites, with few services and a single framework. But when you multiply frameworks x services x servers the scripts get ugly real quick. Using Bus plugins allows you to decouple the definition of site-wide services from their attachment and execution.

Hosted by WebFaction

Log in as guest/cpguest to create tickets