Added initial signal handling
import asyncio
import functools
+import signal
+import sys
import uvloop
@@ -19,6 +21,11 @@ class UvicornWorker(Worker):
* `httptools` as the HTTP request parser.
"""
+ def __init__(self, *args, **kwargs): # pragma: no cover
+ super().__init__(*args, **kwargs)
+ self.servers = []
+ self.exit_code = 0
+
def init_process(self):
# Close any existing event loop before setting a
# new policy.
@@ -34,8 +41,45 @@ class UvicornWorker(Worker):
def run(self):
loop = asyncio.get_event_loop()
loop.create_task(self.create_servers(loop))
- loop.create_task(tick(loop, self.notify))
+ loop.create_task(self.tick(loop))
loop.run_forever()
+ sys.exit(self.exit_code)
+
+ def init_signals(self):
+ # Set up signals through the event loop API.
+ loop = asyncio.get_event_loop()
+
+ loop.add_signal_handler(signal.SIGQUIT, self.handle_quit,
+ signal.SIGQUIT, None)
+
+ loop.add_signal_handler(signal.SIGTERM, self.handle_exit,
+ signal.SIGTERM, None)
+
+ loop.add_signal_handler(signal.SIGINT, self.handle_quit,
+ signal.SIGINT, None)
+
+ loop.add_signal_handler(signal.SIGWINCH, self.handle_winch,
+ signal.SIGWINCH, None)
+
+ loop.add_signal_handler(signal.SIGUSR1, self.handle_usr1,
+ signal.SIGUSR1, None)
+
+ loop.add_signal_handler(signal.SIGABRT, self.handle_abort,
+ signal.SIGABRT, None)
+
+ # Don't let SIGTERM and SIGUSR1 disturb active requests
+ # by interrupting system calls
+ signal.siginterrupt(signal.SIGTERM, False)
+ signal.siginterrupt(signal.SIGUSR1, False)
+
+ def handle_quit(self, sig, frame):
+ self.alive = False
+ self.cfg.worker_int(self)
+
+ def handle_abort(self, sig, frame):
+ self.alive = False
+ self.exit_code = 1
+ self.cfg.worker_abort(self)
async def create_servers(self, loop):
cfg = self.cfg
@@ -46,14 +90,19 @@ class UvicornWorker(Worker):
http.HttpProtocol,
consumer=consumer, loop=loop, sock=sock, cfg=cfg
)
- await loop.create_server(protocol, sock=sock)
-
+ server = await loop.create_server(protocol, sock=sock)
+ self.servers.append(server)
-async def tick(loop, notify):
+ async def tick(self, loop):
cycle = 0
- while True:
+ while self.alive:
http.set_time_and_date()
cycle = (cycle + 1) % 10
if cycle == 0:
- notify()
+ self.notify()
await asyncio.sleep(1)
+
+ for server in self.servers:
+ server.close()
+ await server.wait_closed()
+ loop.stop()
