QTZPOC-20

QTZPOC-20: Improve worker shutdown handling by allowing SystemExit and KeyboardInterrupt to propagate directly, preserving their original exit codes and ensuring cleanup.
This commit is contained in:
2026-09-10 14:25:08 -03:00
parent 6c0d178f99
commit bf48a18c7b

View File

@@ -305,22 +305,22 @@ async def main():
# This will run the workers and wait for them to complete.
# If an exception occurs in any of the worker handlers, it will be propagated here.
await asyncio.gather(*handlers)
except (SystemExit, KeyboardInterrupt) as e:
# Deliberate shutdown (Ctrl+C, a handler's own sys.exit) — not a failure to log as one.
# `finally` below calls sys.exit(exit_code) unconditionally, which supersedes this raise
# and becomes the exception that actually propagates — the raise is here so this branch
# still honors the reraise-on-SystemExit contract, not because it changes what exits.
exit_code = e.code if isinstance(e, SystemExit) and isinstance(e.code, int) else 0
raise
except Exception as e:
logger.custom_error(f'An unhandled exception occurred: {e}', metadata_runtime)
exit_code = 1
finally:
# No `except (SystemExit, KeyboardInterrupt)` on purpose: `finally` runs on every path,
# caught or not, so cleanup still happens for a deliberate shutdown (Ctrl+C, a handler's
# own sys.exit) without us having to catch and re-raise it ourselves — which would only
# let us relabel its exit code before `sys.exit(exit_code)` below discards it anyway.
# Letting it propagate on its own keeps the original code (e.g. a handler's sys.exit(N))
# intact instead of collapsing it to 0.
if notification_handler:
notification_handler.shutdown()
if activities:
await activities.shutdown()
metrics.APP_UP.labels(pod_id=POD_ID).set(0) # Mark app as DOWN
sys.exit(exit_code)