aiosqlite
aiosqlite copied to clipboard
Allow the lifetime of the Connection thread to be tied to an event loop
Description
In projects where aiosqlite is used just as an async replacement for the sqlite3 module, it's not always possible to refactor downstream codebases to use async context managers and gracefully close aiosqlite. This results in undesirable behavior like Ctrl+C not immediately working, failing integration tests locking up test runners (how I found out GitHub Actions can run for six hours 😄), and the user eventually mashing Ctrl+C to kill the process anyways.
For the common use case with only a single event loop, tying the lifetime of the Connection object to this event loop with an optional keyword argument will allow aiosqlite to gracefully close the database connection without breaking any existing code. To increase responsiveness, you could even lower the queue polling timeout from 0.1 to 0.01.
Related issues:
- https://github.com/omnilib/aiosqlite/issues/74
- https://github.com/omnilib/aiosqlite/pull/82#issuecomment-742134720
The lint error with Python 3.7 and 3.8 is unrelated to this PR but can be fixed with # pylint: disable=too-many-ancestors or the appropriate pylint config:
[DESIGN]
max-parents=9
Agreed. I'm still doing some more testing (specifically preventing IPython lockups when using aiosqlite within an interactive session) but maybe it's better to keep track of every observed event loop via get_loop?
Alternatively, maybe it's better to make the thread daemonic and possibly clean up when the thread is killed (if that is possible)? Or use a second daemon thread to signal the main thread to exit? Or atexit.register? I'm just thinking aloud, when I get some time I'll try these approaches out to see which work.
The "parent event loop" thing was just my original idea, I don't particularly care about the implementation details as long as the database is gracefully closed and the interpreter isn't stuck waiting for this thread when it exits.