import asyncio import signal import ssl import sys from components.cluster.cluster import cluster from components.web import * from contextlib import asynccontextmanager from hypercorn.asyncio import serve from hypercorn.config import Config from hypercorn.middleware import ProxyFixMiddleware hypercorn_config = Config() hypercorn_config.bind = [defaults.HYPERCORN_BIND] hypercorn_config.certfile = defaults.TLS_CERTFILE hypercorn_config.keyfile = defaults.TLS_KEYFILE hypercorn_config.include_server_header = False hypercorn_config.server_names = defaults.HOSTNAME hypercorn_config.ciphers = "ECDHE+AESGCM" hypercorn_shutdown_event = asyncio.Event() def handle_shutdown() -> None: hypercorn_shutdown_event.set() @asynccontextmanager async def lifespan(): def _exception_handler(loop, context): exception = context.get("exception") if isinstance(exception, ssl.SSLError) or isinstance( exception, asyncio.sslproto._SSLProtocolTransport ): pass elif isinstance(exception, OSError) and exception.errno == 99: print("ERROR: Unable to bind to an address") hypercorn_shutdown_event.set() else: loop.default_exception_handler(context) loop = asyncio.get_running_loop() loop.set_exception_handler(_exception_handler) for sig in (signal.SIGINT, signal.SIGTERM): loop.add_signal_handler(sig, handle_shutdown) try: yield finally: print("Lifespan ended") sys.exit(0) async def main(): async with lifespan(): tasks = [ asyncio.create_task( serve( ProxyFixMiddleware(app, mode="legacy", trusted_hops=1), hypercorn_config, shutdown_trigger=hypercorn_shutdown_event.wait, ), name="qrt", ), asyncio.create_task( cluster.run(shutdown_trigger=hypercorn_shutdown_event), name="cluster", ), ] await hypercorn_shutdown_event.wait() print("Shutting down") for task in tasks: task.cancel() async with asyncio.timeout(1): await asyncio.gather(*tasks, return_exceptions=True) asyncio.run(main())