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:
- 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.
- 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.
- 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() Persistence(cherrypy.engine, config['connstr']).subscribe() cherrypy.engine.start() cherrypy.engine.block()
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.

