Added async lock to database transactions to prevent concurrent transaction conflicts.
This commit is contained in:
+13
-9
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
"""Async SQLite database access for Crabstero's persistent storage."""
|
"""Async SQLite database access for Crabstero's persistent storage."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from typing import TYPE_CHECKING, NamedTuple, Self
|
from typing import TYPE_CHECKING, NamedTuple, Self
|
||||||
|
|
||||||
@@ -109,21 +110,24 @@ class Database:
|
|||||||
:param connection: An open aiosqlite connection.
|
:param connection: An open aiosqlite connection.
|
||||||
"""
|
"""
|
||||||
self._connection = connection
|
self._connection = connection
|
||||||
|
self._tx_lock = asyncio.Lock()
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def _transaction(self) -> AsyncIterator[None]:
|
async def _transaction(self) -> AsyncIterator[None]:
|
||||||
"""Begin an immediate write transaction.
|
"""Begin an immediate write transaction.
|
||||||
|
|
||||||
Commits on success, rolls back on error.
|
Acquires an async lock so that only one transaction runs at a
|
||||||
|
time, then commits on success or rolls back on error.
|
||||||
"""
|
"""
|
||||||
await self._connection.execute("BEGIN IMMEDIATE")
|
async with self._tx_lock:
|
||||||
try:
|
await self._connection.execute("BEGIN IMMEDIATE")
|
||||||
yield
|
try:
|
||||||
except BaseException:
|
yield
|
||||||
await self._connection.rollback()
|
except BaseException:
|
||||||
raise
|
await self._connection.rollback()
|
||||||
else:
|
raise
|
||||||
await self._connection.commit()
|
else:
|
||||||
|
await self._connection.commit()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def connect(cls, path: str) -> Self:
|
async def connect(cls, path: str) -> Self:
|
||||||
|
|||||||
Reference in New Issue
Block a user