Rework shutdown logic (#6659)

Co-authored-by: Kowlin <10947836+Kowlin@users.noreply.github.com>
This commit is contained in:
Jakub Kuczys
2026-03-03 22:45:23 +01:00
committed by GitHub
parent 07e6f1b264
commit 18154465c3

View File

@@ -422,20 +422,13 @@ def handle_early_exit_flags(cli_flags: Namespace):
sys.exit(ExitCodes.INVALID_CLI_USAGE) sys.exit(ExitCodes.INVALID_CLI_USAGE)
async def shutdown_handler(red, signal_type=None, exit_code=None): async def signal_shutdown_handler(red: Red, signal_type: signal.Signals) -> NoReturn:
if signal_type: log.info("%s received. Quitting...", signal_type.name)
log.info("%s received. Quitting...", signal_type.name) sys.exit(ExitCodes.SHUTDOWN)
# Do not collapse the below line into other logic
# We need to renter this function
# after it interrupts the event loop.
sys.exit(ExitCodes.SHUTDOWN)
elif exit_code is None:
log.info("Shutting down from unhandled exception")
red._shutdown_mode = ExitCodes.CRITICAL
if exit_code is not None:
red._shutdown_mode = exit_code
async def shutdown_handler(red: Red, exit_code: int) -> None:
red._shutdown_mode = exit_code
try: try:
if not red.is_closed(): if not red.is_closed():
await red.close() await red.close()
@@ -473,7 +466,8 @@ def red_exception_handler(red, red_task: asyncio.Future):
except Exception as exc: except Exception as exc:
log.critical("The main bot task didn't handle an exception and has crashed", exc_info=exc) log.critical("The main bot task didn't handle an exception and has crashed", exc_info=exc)
log.warning("Attempting to die as gracefully as possible...") log.warning("Attempting to die as gracefully as possible...")
asyncio.create_task(shutdown_handler(red)) log.info("Shutting down from unhandled exception")
sys.exit(ExitCodes.CRITICAL)
def main(): def main():
@@ -507,7 +501,7 @@ def main():
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT) signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
for s in signals: for s in signals:
loop.add_signal_handler( loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(shutdown_handler(red, s)) s, lambda s=s: asyncio.create_task(signal_shutdown_handler(red, s))
) )
exc_handler = functools.partial(global_exception_handler, red) exc_handler = functools.partial(global_exception_handler, red)
@@ -524,7 +518,7 @@ def main():
log.warning("Please do not use Ctrl+C to Shutdown Red! (attempting to die gracefully...)") log.warning("Please do not use Ctrl+C to Shutdown Red! (attempting to die gracefully...)")
log.error("Received KeyboardInterrupt, treating as interrupt") log.error("Received KeyboardInterrupt, treating as interrupt")
if red is not None: if red is not None:
loop.run_until_complete(shutdown_handler(red, signal.SIGINT)) loop.run_until_complete(signal_shutdown_handler(red, signal.SIGINT))
except SystemExit as exc: except SystemExit as exc:
# We also have to catch this one here. Basically any exception which normally # We also have to catch this one here. Basically any exception which normally
# Kills the python interpreter (Base Exceptions minus asyncio.cancelled) # Kills the python interpreter (Base Exceptions minus asyncio.cancelled)
@@ -536,11 +530,11 @@ def main():
exit_code_name = "UNKNOWN" exit_code_name = "UNKNOWN"
log.info("Shutting down with exit code: %s (%s)", exit_code, exit_code_name) log.info("Shutting down with exit code: %s (%s)", exit_code, exit_code_name)
if red is not None: if red is not None:
loop.run_until_complete(shutdown_handler(red, None, exc.code)) loop.run_until_complete(shutdown_handler(red, exc.code))
except Exception as exc: # Non standard case. except Exception as exc: # Non standard case.
log.exception("Unexpected exception (%s): ", type(exc), exc_info=exc) log.exception("Unexpected exception (%s): ", type(exc), exc_info=exc)
if red is not None: if red is not None:
loop.run_until_complete(shutdown_handler(red, None, ExitCodes.CRITICAL)) loop.run_until_complete(shutdown_handler(red, ExitCodes.CRITICAL))
finally: finally:
# Allows transports to close properly, and prevent new ones from being opened. # Allows transports to close properly, and prevent new ones from being opened.
# Transports may still not be closed correctly on windows, see below # Transports may still not be closed correctly on windows, see below