aiosqlite
aiosqlite copied to clipboard
Aiosqlite leaves thread hanging
class ProxyClass:
def __init__(self):
self._conn = None
self._connected = False
async def connect(self):
self._conn = await aiosqlite.connect(':memory:')
self._connected = True
def close(self):
await self._conn.close()
self._connected = False
def __getattr__(self, name):
return getattr(self._conn, name)
async def run():
db = ProxyClass()
await db.connect()
try:
#perform some long running db updates
#commit changes
finally:
await db.close()
I import this in a script and call run using asyncio.run(run()). It finishes but the program never exits because the thread does not get stopped and ctrl+c spits following.
^CException ignored in: <module 'threading' from '/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py'> Traceback (most recent call last): File "/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/threading.py", line 1448, in _shutdown lock.acquire() KeyboardInterrupt:
I can’t replicate this with the example code. Are you sure your “long running db updates” have actually completed before pressing ctrl-c? Can you provide more insight on what that long running functionality entails?
Hello I have the same problem. But in my case its short select for two rows in result.
I have found that it happens when you have multiple connections (aka multiple threads).
import aiosqlite import asyncio
class ProxyClass:
def __init__(self):
self._conn = None
self._connected = False
async def connect(self):
self._conn = await aiosqlite.connect(':memory:')
self._connected = True
async def close(self):
await self._conn.close()
self._connected = False
def __getattr__(self, name):
return getattr(self._conn, name)
class DBRunner:
def __init__(self):
self._dbs = {
"db1": ProxyClass(),
"db2": ProxyClass()
}
async def init_dbs(self):
await asyncio.gather(
*[db.connect() for db in self._dbs.values()]
)
async def close_dbs(self):
for db in self._dbs.values():
await db.close()
async def run(self, name):
db = self._dbs[name]
await db.execute("CREATE TABLE memview_v1 (X, Y)")
await db.execute("INSERT INTO memview_v1 (X, Y) VALUES(1,2)")
await db.commit()
async def main():
runner = DBRunner()
try:
await runner.init_dbs()
await asyncio.gather(*[runner.run(name) for name in ('db1', 'db2')])
finally:
await runner.close_dbs()
asyncio.run(main())
for each connection a separate thread is created. The actual code makes thousands of inserts updates and deletes to disk based db connection, but I ensure to call db.close() of each db in my finally block. The program never really exits and the shell hangs and ctrl+c yields that output
Got hanging by the following code at MacOS with python3.10 and aiosqlite==0.20.0
import asyncio
from contextlib import asynccontextmanager
import aiosqlite
@asynccontextmanager
async def open_db():
async with aiosqlite.connect("db.sqlite3"):
yield
@asynccontextmanager
async def nest_open():
async with open_db():
yield
async def gen():
async with nest_open():
yield
async def main():
async for _ in gen():
raise TypeError()
asyncio.run(main())
Related issue #306
Dirty workaround while we wait for a release with the daemon option:
import asyncio
import aiosqlite
from aiosqlite import Cursor
async def main():
awaitable_db = aiosqlite.connect(":memory:")
# thread not started yet. It starts in the `__await__` method
awaitable_db.daemon = True
# Now it will start with daemon == True
db = await awaitable_db
cursor: Cursor = await db.execute("select 1")
print(await cursor.fetchone())
if __name__ == "__main__":
asyncio.run(main())
Please see https://github.com/omnilib/aiosqlite/issues/299#issuecomment-2630067292