Add FastAPI database transaction management strategy and update requirements
Introduce a new technical specification for managing database transactions in FastAPI, ensuring ACID compliance through standardized practices. The specification outlines transaction handling for API endpoints, CRUD functions, and non-API operations, emphasizing the use of context managers and error handling. Additionally, update the requirements file to include new testing dependencies for async operations, enhancing the testing framework for the application.
This commit is contained in:
parent
d6d19397d3
commit
c8cdbd571e
57
.cursor/rules/fastapi-db-strategy.mdc
Normal file
57
.cursor/rules/fastapi-db-strategy.mdc
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
description: FastAPI Database Transactions
|
||||||
|
globs:
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
## FastAPI Database Transaction Management: Technical Specification
|
||||||
|
|
||||||
|
**Objective:** Ensure atomic, consistent, isolated, and durable (ACID) database operations through a standardized transaction management strategy.
|
||||||
|
|
||||||
|
**1. API Endpoint Transaction Scope (Primary Strategy):**
|
||||||
|
|
||||||
|
* **Mechanism:** A FastAPI dependency `get_transactional_session` (from `app.database` or `app.core.dependencies`) wraps database-modifying API request handlers.
|
||||||
|
* **Behavior:**
|
||||||
|
* `async with AsyncSessionLocal() as session:` obtains a session.
|
||||||
|
* `async with session.begin():` starts a transaction.
|
||||||
|
* **Commit:** Automatic on successful completion of the `yield session` block (i.e., endpoint handler success).
|
||||||
|
* **Rollback:** Automatic on any exception raised from the `yield session` block.
|
||||||
|
* **Usage:** Endpoints performing CUD (Create, Update, Delete) operations **MUST** use `db: AsyncSession = Depends(get_transactional_session)`.
|
||||||
|
* **Read-Only Endpoints:** May use `get_async_session` (alias `get_db`) or `get_transactional_session` (results in an empty transaction).
|
||||||
|
|
||||||
|
**2. CRUD Layer Function Design:**
|
||||||
|
|
||||||
|
* **Transaction Participation:** CRUD functions (in `app/crud/`) operate on the session provided by the caller.
|
||||||
|
* **Composability Pattern:** Employ `async with db.begin_nested() if db.in_transaction() else db.begin():` to wrap database modification logic within the CRUD function.
|
||||||
|
* If an outer transaction exists (e.g., from `get_transactional_session`), `begin_nested()` creates a **savepoint**. The `async with` block commits/rolls back this savepoint.
|
||||||
|
* If no outer transaction exists (e.g., direct call from a script), `begin()` starts a **new transaction**. The `async with` block commits/rolls back this transaction.
|
||||||
|
* **NO Direct `db.commit()` / `db.rollback()`:** CRUD functions **MUST NOT** call these directly. The `async with begin_nested()/begin()` block and the outermost transaction manager are responsible.
|
||||||
|
* **`await db.flush()`:** Use only when necessary within the `async with` block to:
|
||||||
|
1. Obtain auto-generated IDs for subsequent operations in the *same* transaction.
|
||||||
|
2. Force database constraint checks mid-transaction.
|
||||||
|
* **Error Handling:** Raise specific custom exceptions (e.g., `ListNotFoundError`, `DatabaseIntegrityError`). These exceptions will trigger rollbacks in the managing transaction contexts.
|
||||||
|
|
||||||
|
**3. Non-API Operations (Background Tasks, Scripts):**
|
||||||
|
|
||||||
|
* **Explicit Management:** These contexts **MUST** manage their own session and transaction lifecycles.
|
||||||
|
* **Pattern:**
|
||||||
|
```python
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
async with session.begin(): # Manages transaction for the task's scope
|
||||||
|
try:
|
||||||
|
# Call CRUD functions, which will participate via savepoints
|
||||||
|
await crud_operation_1(db=session, ...)
|
||||||
|
await crud_operation_2(db=session, ...)
|
||||||
|
# Commit is handled by session.begin() context manager on success
|
||||||
|
except Exception:
|
||||||
|
# Rollback is handled by session.begin() context manager on error
|
||||||
|
raise
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Key Principles Summary:**
|
||||||
|
|
||||||
|
* **API:** `get_transactional_session` for CUD.
|
||||||
|
* **CRUD:** Use `async with db.begin_nested() if db.in_transaction() else db.begin():`. No direct commit/rollback. Use `flush()` strategically.
|
||||||
|
* **Background Tasks:** Explicit `AsyncSessionLocal()` and `session.begin()` context managers.
|
||||||
|
|
||||||
|
|
||||||
|
This strategy ensures a clear separation of concerns, promotes composable CRUD operations, and centralizes final transaction control at the appropriate layer.
|
@ -17,3 +17,8 @@ email-validator>=2.0.0
|
|||||||
fastapi-users[oauth]>=12.1.2
|
fastapi-users[oauth]>=12.1.2
|
||||||
authlib>=1.3.0
|
authlib>=1.3.0
|
||||||
itsdangerous>=2.1.2
|
itsdangerous>=2.1.2
|
||||||
|
pytest>=7.4.0
|
||||||
|
pytest-asyncio>=0.21.0
|
||||||
|
pytest-cov>=4.1.0
|
||||||
|
httpx>=0.24.0 # For async HTTP testing
|
||||||
|
aiosqlite>=0.19.0 # For async SQLite support in tests
|
Loading…
Reference in New Issue
Block a user