--
Chris
def main ():
def sighup_handler (server, loop, signum, frame):
server.stop ()
loop.stop ()
server = tornado.httpserver.HTTPServer (...)
loop = tornado.ioloop.IOLoop.instance (
signal.signal (signal.SIGHUP,
lambda s, f: sighup_handler (server, loop, s, f))
Seems to work here, but I'm wondering what you meant by "after a delay".
It will happen after a delay or I need to introduce a delay?
Cliff
It worked well enough since it did most of the necessary unbind, fork,
and exit. With nginx in front of it, existing and new connections were
unaffected.
I'm actually using this in an unrelated, but similar, situation where I
run a bunch of database-related callbacks in an IOLoop (part of an
install procedure) and I want to exit when they are all finished. What
I'm using right now is this:
def shutdown ():
if not ioloop._callbacks:
ioloop.stop ()
raise SystemExit
PeriodicCallback (shutdown, 1000, ioloop).start ()
This seems to work nicely, with the notable exception of relying on an
implementation detail to get the job done. Having the aforementioned
method would solve this.
Regards,
Cliff
Regards,
Cliff
callbacks = self._callbacks
self._callbacks = []
for callback in callbacks:
self._run_callback(callback)
Back to the drawing board :P I was trying to get away with not
modifying Tornado itself, but that's appearing like a fairly remote
possibility at this point.
Cliff
On Wed, 2011-03-02 at 01:51 -0800, Cliff Wells wrote:
--Chris
--
Chris
So I think what is needed is an additional method IOLoop.has_callbacks()
that can be used to see if there are pending callbacks.
Yeah I'm not sure it's worth it. For the clean shutdown case, waiting
an arbitrary amount of time is probably acceptable, if not pretty. For
the case I was just dealing with (a one-shot IOLoop) I ended up
refactoring enough during the learning process that I no longer need
that process to be a one-shot deal (and hey, it's better), so the issue
is moot there.
As much as I dislike arbitrary constants, I don't think this rarely used
case justifies adding any significant overhead, unless the feature can
be leveraged to cover more interesting and frequently-used problems.
I'm currently not thinking of any.
Regards,
Cliff
def start_httpserver(app_root, handler_map, opts): # create app and http server app = Application(handler_map, app_root, opts) http_server = tornado.httpserver.HTTPServer(app, xheaders=True) ioloop = tornado.ioloop.IOLoop.instance() def mem_check_scheduler(): easylog.debug("Call Check MEM") rss_mem = systool.mem('rss') / 1024 if rss_mem > app.sandbox_conf['restart_mem']: easylog.error("RSS: %d MB Need to restart", rss_mem) os.kill(os.getpid(), signal.SIGUSR1) mem_check_scheduler = tornado.ioloop.PeriodicCallback(mem_check_scheduler, 1000 * app.sandbox_conf['mem_check_sec']) mem_check_scheduler.start() def restart_self(): easylog.error("Stopping the server") http_server.stop() # dont accept the new request mem_check_scheduler.stop() deadline = time.time() + 10 def stop_loop(): now = time.time() easylog.error("wait for ioloop finsh. %d", now) if now < deadline and ioloop._callbacks: ioloop.add_timeout(now+1, stop_loop) else: ioloop.stop() easylog.error("IOLOOP stopped") #restart code comes from autoreload.py in tornado try: os.execv(sys.executable, [sys.executable] + sys.argv) except OSError: # Mac OS X versions prior to 10.6 do not support execv in # a process that contains multiple threads. Instead of # re-executing in the current process, start a new one # and cause the current process to exit. This isn't # ideal since the new process is detached from the parent # terminal and thus cannot easily be killed with ctrl-C, # but it's better than not being able to autoreload at # all. # Unfortunately the errno returned in this case does not # appear to be consistent, so we can't easily check for # this error specifically. os.spawnv(os.P_NOWAIT, sys.executable, [sys.executable] + sys.argv) sys.exit(0) stop_loop() def shutdown(): easylog.error("Stopping the server") http_server.stop() # dont accept the new request mem_check_scheduler.stop() deadline = time.time() + 10 def stop_loop(): now = time.time() easylog.error("wait for ioloop finsh. %d", now) if now < deadline and ioloop._callbacks: ioloop.add_timeout(now+1, stop_loop) else: ioloop.stop() easylog.error("IOLOOP stopped") sys.exit(1) stop_loop() def exit_handler(sig, frame): easylog.error("#### Caught signal:%d will exit ####", sig) ioloop.spawn_callback(shutdown) signal.signal(signal.SIGTERM, exit_handler) signal.signal(signal.SIGINT, exit_handler) signal.signal(signal.SIGABRT, exit_handler) def restart_handler(sig, frame): easylog.error("#### Caught signal:%d will restart self ####", sig) ioloop.spawn_callback(restart_self) signal.signal(signal.SIGPIPE, restart_handler) signal.signal(signal.SIGUSR1, restart_handler) # start http server if opts.debug == True: http_server.listen(opts.port, address=opts.address) else: http_server.bind(opts.port, address=opts.address) http_server.start(num_processes=opts.process) easylog.info('listen @ %s:%d' % (opts.address, opts.port)) ioloop.start()