Last active
August 29, 2015 14:01
-
-
Save proteneer/a1bd29592809e1457f8d to your computer and use it in GitHub Desktop.
tornado + redis
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
import tornado.web | |
import tornado.httpserver | |
import tornado.ioloop | |
import process2 | |
import tornado.netutil | |
import redis | |
import signal | |
import time | |
import sys | |
import os | |
import subprocess | |
def preexec(): # Don't forward signals. | |
os.setpgrp() | |
def init_redis(redis_options, cwd=None): | |
""" Spawn a redis subprocess port and returns a redis client. """ | |
print("Creating redis subprocess on ", process2.task_id()) | |
redis_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), | |
'..', 'redis', 'src', 'redis-server') | |
redis_path = os.path.abspath(redis_path) | |
args = [redis_path] | |
for option_name, option_value in redis_options.items(): | |
args.append('--'+option_name) | |
args.append(str(option_value)) | |
redis_process = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec) | |
if redis_process.poll() is not None: | |
print('Could not start redis server, aborting') | |
sys.exit(0) | |
redis_port = redis_options['port'] | |
redis_client = redis.Redis(host='localhost', port=int(redis_port), | |
decode_responses=True) | |
# poll until redis server is alive | |
alive = False | |
start_time = time.time() | |
while time.time()-start_time < 15.0: | |
try: | |
alive = redis_client.ping() | |
break | |
except Exception: | |
pass | |
if not alive: | |
raise ValueError('Could not start redis') | |
return redis_client | |
class ExampleApp(tornado.web.Application): | |
def __init__(self, db): | |
self.db = db | |
super(ExampleApp, self).__init__([]) | |
def shutdown(self): | |
tornado.ioloop.IOLoop.instance().stop() | |
def stop_parent(sig, frame): | |
pass | |
def stop_children(sig, frame): | |
print('-> stopping children', process2.task_id()) | |
# stop accepting new requests | |
server.stop() | |
# wait for all the locks to expire | |
deadline = time.time() + 10 | |
io_loop = tornado.ioloop.IOLoop.instance() | |
def stop_loop(): | |
now = time.time() | |
if now < deadline and app.db.zrange('locks', 0, -1): | |
io_loop.add_timeout(now + 1, stop_loop) | |
else: | |
app.shutdown() | |
stop_loop() | |
def start(): | |
redis_options = { | |
'port': 2873, | |
'appendfilename': 'redis.aof', | |
'logfile': 'redis.log', | |
} | |
db = init_redis(redis_options) | |
global app | |
app = ExampleApp(db) | |
global server | |
sockets = tornado.netutil.bind_sockets(9873) | |
# forces parent to ignore Ctrl-C exits | |
signal.signal(signal.SIGINT, stop_parent) | |
signal.signal(signal.SIGTERM, stop_parent) | |
try: | |
process2.fork_processes(0) | |
signal.signal(signal.SIGINT, stop_children) | |
signal.signal(signal.SIGTERM, stop_children) | |
server = tornado.httpserver.HTTPServer(app) | |
server.add_sockets(sockets) | |
tornado.ioloop.IOLoop.instance().start() | |
except SystemExit as e: | |
print('parent is shutting down ...', e) | |
app.db.shutdown() | |
sys.exit(0) | |
start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment