Created
August 23, 2012 06:32
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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