Skip to content

Instantly share code, notes, and snippets.

@ionrock
Created August 23, 2012 06:32
Show Gist options
  • Save ionrock/3433405 to your computer and use it in GitHub Desktop.
Save ionrock/3433405 to your computer and use it in GitHub Desktop.
Trying out an idea where a single cherrypy process clones itself in order to serve the same application on different ports. Signals sent to the initial process would be propagated to the children via ZeroMQ and the Web Site Process Bus in CherryPy (cherry
"""
CP Cluster
Create a cluster of CherryPy application processes. This will take an
single cherrypy application and create multiple instances on
difference processes using sequential port numbers.
"""
from __future__ import print_function
import os
import tempfile
import threading
import urllib
import time
import zmq
import cherrypy
from cherrypy.process.plugins import SimplePlugin
class ClusterMain(SimplePlugin):
"""
Define our master cherrypy application.
"""
def __init__(self, bus, instances=None):
super(ClusterMain, self).__init__(bus)
self.ctx = zmq.Context()
self.sock = self._setup_socket()
self.instances = instances
self.procs = []
def _setup_socket(self):
sock = self.ctx.socket(zmq.PUB)
if hasattr(self, 'uri'):
uri = self.uri
else:
# use the ipc interface
fd, name = tempfile.mkstemp()
uri = 'ipc://%s' % name
sock.setsockopt(zmq.LINGER, 1000)
sock.connect(uri)
self.uri = uri
return sock
def wait_for_http(self, port):
tries = 5
while tries:
try:
doc = urllib.urlopen('http://localhost:%s' % port)
break
except:
time.sleep(1)
tries -= 1
def run(self, port):
for i in range(self.instances):
port = port + 1
print('parent starting', port)
# update our port
cherrypy.config.update({'server_socket.port': port})
pid = os.fork()
if pid == 0:
self.setup_member()
else:
self.wait_for_http(port)
def setup_member(self):
# create our member plugin
cherrypy.engine.member = ClusterMember(cherrypy.engine)
cherrypy.engine.member.uri = self.uri
cherrypy.engine.member.subscribe()
print('starting instance', cherrypy.config)
# start up the app
cherrypy.engine.start()
cherrypy.engine.block()
def stop(self):
self.sock.send('stop')
class ClusterMember(SimplePlugin):
"""
Starts a thread listening to its zmq socket for events.
"""
uri = None
def start(self):
self.thread = threading.Thread(target=self.listen)
self.thread.start()
def listen(self):
ctx = zmq.Context()
sock = ctx.socket(zmq.SUB)
sock.setsockopt(zmq.SUBSCRIBE, '')
sock.connect(self.uri)
while not self.bus.state == self.bus.states.STOPPED:
msg = sock.recv()
self.bus.publish(msg)
if __name__ == '__main__':
class Root(object):
@cherrypy.expose
def index(self):
return 'Hello world!'
cherrypy.tree.mount(Root(), '/')
bus = cherrypy.process.wspbus.Bus()
master = ClusterMain(bus, 2)
master.subscribe()
master.run(8080)
master.start()
master.block()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment