Simplify shutdown handling for graceful cleanup#135
Conversation
Replace complex signal-based shutdown with simpler try/finally cleanup: - Remove custom signal handlers that called sys.exit() from async code - Use try/finally in main() to ensure cleanup() is always called - Handle KeyboardInterrupt in __init__.py to suppress traceback on Ctrl+C - Remove unused imports (asyncio, signal, sys) from server.py - Rename shutdown() to cleanup() to reflect its simpler purpose This approach: - Lets Python's default signal handling work naturally - Avoids "asyncio.run() cannot be called from a running event loop" errors - Ensures database connections are closed on any exit path - Is simpler and more maintainable Based on work by @ahmedmustahid in #78. Co-Authored-By: Ahmed Mustahid <[email protected]> Co-Authored-By: Claude Opus 4.5 <[email protected]>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d00d517313
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| finally: | ||
| # Clean up database connections on exit | ||
| await cleanup() |
There was a problem hiding this comment.
Ensure cleanup runs under cancellation
When the server is interrupted (SIGINT/SIGTERM), asyncio.run() cancels the main() task; that cancellation propagates into the finally block and will cancel the awaited cleanup() call unless it is shielded or the CancelledError is handled. In that case, db_connection.close() may never run, so database connections can remain open on Ctrl+C despite the new shutdown simplification. Consider shielding cleanup() or catching CancelledError so cleanup completes even under cancellation.
Useful? React with 👍 / 👎.
Add explicit version constraints for transitive dependencies to fix: - h11 >=0.16.0 (Critical: malformed Chunked-Encoding bodies) - aiohttp >=3.13.3 (High: zip bomb in auto_decompress) - urllib3 >=2.6.3 (High: decompression bomb issues) - starlette >=0.49.1 (High: O(n²) DoS via Range header) - requests >=2.32.4 (Medium: .netrc credential leak) Co-Authored-By: Claude Opus 4.5 <[email protected]>
This reverts commit bec200f.
Summary
Simplify the shutdown handling by replacing complex signal-based shutdown with a cleaner try/finally approach.
Problem
The previous implementation used custom signal handlers that called
sys.exit()from async code, which could cause:Solution
sys.exit()from async codemain()to ensurecleanup()is always calledKeyboardInterruptin__init__.pyto suppress traceback on Ctrl+Casyncio,signal,sys) from server.pyshutdown()tocleanup()to reflect its simpler purposeThis approach:
Attribution
Based on work by @ahmedmustahid in #78. This PR extracts and simplifies just the shutdown handling portion.
Test plan
🤖 Generated with Claude Code