Reputation: 11
Uvicorn will not run inside thread because signals don't work in threads. Just removing the signal handling stops server from closing (needs to be forcefully shut down)
My solution was interferring with the __new__
function to get the server object and creating a shutdown function, and then binding that to a signal outside the thread.
However this is a really ugly solution. Are there better ways?
def run():
'''
Start uvicorn server
returns exit function
'''
server = None
old_new = uvicorn.Server.__new__
def spoof_server(self, *_, **__):
'''Interfeer with __new__ to set server'''
nonlocal server
server = old_new(self)
return server
uvicorn.Server.__new__ = spoof_server
uvicorn.Server.install_signal_handlers = lambda *_, **__: None
Thread(target=uvicorn.run, args=[make_app()]).start()
def exit_server():
print('exiting...')
server.handle_exit(None, None)
return exit_server
Upvotes: 1
Views: 7537
Reputation: 21
I was looking for something like this as well. I found this answer that helped me. https://stackoverflow.com/a/64521239/13029591
I'll post the snippet here:
import contextlib
import time
import threading
import uvicorn
class Server(uvicorn.Server):
def install_signal_handlers(self):
pass
@contextlib.contextmanager
def run_in_thread(self):
thread = threading.Thread(target=self.run)
thread.start()
try:
while not self.started:
time.sleep(1e-3)
yield
finally:
self.should_exit = True
thread.join()
config = Config("example:app", host="127.0.0.1", port=5000, log_level="info")
server = Server(config=config)
with server.run_in_thread():
# Server is started.
...
# Server will be stopped once code put here is completed
...
# Server stopped.
Upvotes: 2