From aaad55e0762cd268cb6aa075e53d489bc87593a3 Mon Sep 17 00:00:00 2001 From: Alejandro Del Castillo Date: Fri, 10 May 2019 16:17:29 -0500 Subject: [PATCH] Jupyterhub: use previous exit strategy for Windows Windows doesn't have support for signal handling so it can't use the signal handling capabilities of asyncio. Use the previous atexit strategy on the Windows case instead. Signed-off-by: Alejandro Del Castillo --- jupyterhub/app.py | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/jupyterhub/app.py b/jupyterhub/app.py index 815097a8..a0c65fb0 100644 --- a/jupyterhub/app.py +++ b/jupyterhub/app.py @@ -2420,22 +2420,30 @@ class JupyterHub(Application): pc.start() self.log.info("JupyterHub is now running at %s", self.proxy.public_url) + # Use atexit for Windows, it doesn't have signal handling support + if _mswindows: + atexit.register(self.atexit) # register cleanup on both TERM and INT self.init_signal() def init_signal(self): loop = asyncio.get_event_loop() for s in (signal.SIGTERM, signal.SIGINT): - loop.add_signal_handler( - s, lambda s=s: asyncio.ensure_future(self.shutdown_cancel_tasks(s)) - ) - infosignals = [signal.SIGUSR1] - if hasattr(signal, 'SIGINFO'): - infosignals.append(signal.SIGINFO) - for s in infosignals: - loop.add_signal_handler( - s, lambda s=s: asyncio.ensure_future(self.log_status(s)) - ) + if not _mswindows: + loop.add_signal_handler( + s, lambda s=s: asyncio.ensure_future(self.shutdown_cancel_tasks(s)) + ) + else: + signal.signal(s, self.win_shutdown_cancel_tasks) + + if not _mswindows: + infosignals = [signal.SIGUSR1] + if hasattr(signal, 'SIGINFO'): + infosignals.append(signal.SIGINFO) + for s in infosignals: + loop.add_signal_handler( + s, lambda s=s: asyncio.ensure_future(self.log_status(s)) + ) async def log_status(self, sig): """Log current status, triggered by SIGINFO (^T in many terminals)""" @@ -2443,6 +2451,24 @@ class JupyterHub(Application): print_ps_info() print_stacks() + def win_shutdown_cancel_tasks(self, signum, frame): + self.log.critical("Received signalnum %s, , initiating shutdown...", signum) + raise SystemExit(128 + signum) + + _atexit_ran = False + + def atexit(self): + """atexit callback""" + if self._atexit_ran: + return + self._atexit_ran = True + # run the cleanup step (in a new loop, because the interrupted one is unclean) + asyncio.set_event_loop(asyncio.new_event_loop()) + IOLoop.clear_current() + loop = IOLoop() + loop.make_current() + loop.run_sync(self.cleanup) + async def shutdown_cancel_tasks(self, sig): """Cancel all other tasks of the event loop and initiate cleanup""" self.log.critical("Received signal %s, initiating shutdown...", sig.name)