formatting
This commit is contained in:
@@ -33,37 +33,37 @@ Use these concepts as the planning backbone:
|
||||
|
||||
1. Engine lifecycle and ownership:
|
||||
One AsyncEngine per process for each DB URL, created once and disposed explicitly when the app lifecycle ends.
|
||||
See: [references/engine.md](references/engine.md)
|
||||
See the [engine lifecycle reference](references/engine.md).
|
||||
2. Session factory and scope:
|
||||
Use async_sessionmaker for configuration; create one AsyncSession per request or unit-of-work, never shared across concurrent tasks.
|
||||
See: [references/session.md](references/session.md)
|
||||
See the [session management reference](references/session.md).
|
||||
3. Transaction boundaries:
|
||||
Prefer context-managed begin blocks for write units and explicit read-only sessions for queries.
|
||||
See: [references/transactions.md](references/transactions.md)
|
||||
See the [transaction boundaries reference](references/transactions.md).
|
||||
4. Lifespan composition:
|
||||
Compose startup/shutdown resources with AsyncExitStack so cleanup is deterministic and ordered.
|
||||
See: [references/engine.md](references/engine.md)
|
||||
See the [engine lifecycle reference](references/engine.md).
|
||||
5. Dependency injection:
|
||||
Provide sessions via FastAPI dependencies with async generators/context managers, not globals.
|
||||
See: [references/session.md](references/session.md)
|
||||
See the [session management reference](references/session.md).
|
||||
6. Implicit I/O control in ORM:
|
||||
Avoid accidental lazy loads; use explicit eager-loading/refresh strategies for asyncio safety.
|
||||
See: [references/implicit_io.md](references/implicit_io.md)
|
||||
See the [implicit I/O reference](references/implicit_io.md).
|
||||
7. Observability and resilience:
|
||||
Add pool/connection settings, logging, timeout, and health checks as first-class plan items.
|
||||
See: [references/observability.md](references/observability.md)
|
||||
See the [observability reference](references/observability.md).
|
||||
|
||||
### Concept Reference Map
|
||||
|
||||
| Concept | Reference |
|
||||
|---|---|
|
||||
| Engine lifecycle and ownership | [references/engine.md](references/engine.md) |
|
||||
| Session factory and scope | [references/session.md](references/session.md) |
|
||||
| Transaction boundaries | [references/transactions.md](references/transactions.md) |
|
||||
| Lifespan composition | [references/engine.md](references/engine.md) |
|
||||
| Dependency injection | [references/session.md](references/session.md) |
|
||||
| Implicit I/O control in ORM | [references/implicit_io.md](references/implicit_io.md) |
|
||||
| Observability and resilience | [references/observability.md](references/observability.md) |
|
||||
| Engine lifecycle and ownership | [Engine lifecycle reference](references/engine.md) |
|
||||
| Session factory and scope | [Session management reference](references/session.md) |
|
||||
| Transaction boundaries | [Transaction boundaries reference](references/transactions.md) |
|
||||
| Lifespan composition | [Engine lifecycle reference](references/engine.md) |
|
||||
| Dependency injection | [Session management reference](references/session.md) |
|
||||
| Implicit I/O control in ORM | [Implicit I/O reference](references/implicit_io.md) |
|
||||
| Observability and resilience | [Observability reference](references/observability.md) |
|
||||
|
||||
## Decision Points
|
||||
|
||||
@@ -235,6 +235,7 @@ Return the plan as:
|
||||
|
||||
## References
|
||||
|
||||
- SQLAlchemy engine/connections: https://docs.sqlalchemy.org/en/21/core/connections.html
|
||||
- SQLAlchemy asyncio extension: https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html
|
||||
- Python async context managers and AsyncExitStack: https://docs.python.org/3/library/contextlib.html
|
||||
!!! info "Primary sources"
|
||||
- [SQLAlchemy engine and connections](https://docs.sqlalchemy.org/en/21/core/connections.html)
|
||||
- [SQLAlchemy asyncio extension](https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html)
|
||||
- [Python async context managers and AsyncExitStack](https://docs.python.org/3/library/contextlib.html)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Async SQLAlchemy Engine
|
||||
|
||||
Source:
|
||||
- https://docs.sqlalchemy.org/en/21/core/connections.html
|
||||
- https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html
|
||||
- https://docs.sqlalchemy.org/en/21/core/pooling.html#pooling-multiprocessing
|
||||
- https://fastapi.tiangolo.com/advanced/events/
|
||||
!!! info "Primary sources"
|
||||
- [SQLAlchemy connections](https://docs.sqlalchemy.org/en/21/core/connections.html)
|
||||
- [SQLAlchemy asyncio extension](https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html)
|
||||
- [SQLAlchemy pooling and multiprocessing](https://docs.sqlalchemy.org/en/21/core/pooling.html#pooling-multiprocessing)
|
||||
- [FastAPI lifespan events](https://fastapi.tiangolo.com/advanced/events/)
|
||||
|
||||
---
|
||||
|
||||
@@ -16,9 +16,9 @@ Create one async engine per process per database URL and keep it for the app lif
|
||||
- In FastAPI, app startup and shutdown ownership belongs in lifespan.
|
||||
- Use `FastAPI(lifespan=...)` (not startup/shutdown events) for modern lifecycle wiring.
|
||||
|
||||
Practical rule:
|
||||
- Exactly one `create_async_engine(...)` call in app bootstrap code.
|
||||
- Zero `create_async_engine(...)` calls in request handlers.
|
||||
!!! tip "Practical rule"
|
||||
- Exactly one `create_async_engine(...)` call in app bootstrap code.
|
||||
- Zero `create_async_engine(...)` calls in request handlers.
|
||||
|
||||
---
|
||||
|
||||
@@ -69,9 +69,9 @@ Use SQLAlchemy async driver URLs:
|
||||
- PostgreSQL: `postgresql+asyncpg://user:pass@host:5432/dbname`
|
||||
- SQLite: `sqlite+aiosqlite:///./app.db`
|
||||
|
||||
Notes:
|
||||
- Do not mix sync drivers (for example `psycopg2`) with `create_async_engine()`.
|
||||
- Keep URL construction centralized in settings/config, not in feature modules.
|
||||
!!! warning "Driver compatibility"
|
||||
- Do not mix sync drivers, for example `psycopg2`, with `create_async_engine()`.
|
||||
- Keep URL construction centralized in settings/config, not in feature modules.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Preventing Implicit ORM I/O (Asyncio)
|
||||
|
||||
Source:
|
||||
- https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html#preventing-implicit-io-when-using-asyncsession
|
||||
- https://docs.sqlalchemy.org/en/21/orm/queryguide/relationships.html
|
||||
!!! info "Primary sources"
|
||||
- [Preventing implicit I/O with AsyncSession](https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html#preventing-implicit-io-when-using-asyncsession)
|
||||
- [SQLAlchemy relationship loading](https://docs.sqlalchemy.org/en/21/orm/queryguide/relationships.html)
|
||||
|
||||
Status: adopted
|
||||
Decision level: advisory
|
||||
Applies to: api-runtime, workers, tests
|
||||
Last reviewed: 2026-06-17
|
||||
??? abstract "Decision metadata"
|
||||
- Status: adopted
|
||||
- Decision level: advisory
|
||||
- Applies to: api-runtime, workers, tests
|
||||
- Last reviewed: 2026-06-17
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
# DB Observability and Resilience
|
||||
|
||||
Source:
|
||||
- https://docs.sqlalchemy.org/en/21/core/pooling.html
|
||||
- https://docs.sqlalchemy.org/en/21/core/engines.html
|
||||
- https://docs.sqlalchemy.org/en/21/core/events.html
|
||||
- https://fastapi.tiangolo.com/advanced/events/
|
||||
!!! info "Primary sources"
|
||||
- [SQLAlchemy pooling](https://docs.sqlalchemy.org/en/21/core/pooling.html)
|
||||
- [SQLAlchemy engine configuration](https://docs.sqlalchemy.org/en/21/core/engines.html)
|
||||
- [SQLAlchemy events](https://docs.sqlalchemy.org/en/21/core/events.html)
|
||||
- [FastAPI lifespan events](https://fastapi.tiangolo.com/advanced/events/)
|
||||
|
||||
Status: adopted
|
||||
Decision level: mandatory
|
||||
Applies to: api-runtime, workers, tests
|
||||
Last reviewed: 2026-06-17
|
||||
??? abstract "Decision metadata"
|
||||
- Status: adopted
|
||||
- Decision level: mandatory
|
||||
- Applies to: api-runtime, workers, tests
|
||||
- Last reviewed: 2026-06-17
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Async SQLAlchemy Session Management
|
||||
|
||||
Source:
|
||||
- https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html
|
||||
- https://docs.sqlalchemy.org/en/21/orm/session_basics.html
|
||||
- https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/
|
||||
!!! info "Primary sources"
|
||||
- [SQLAlchemy asyncio extension](https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html)
|
||||
- [SQLAlchemy session basics](https://docs.sqlalchemy.org/en/21/orm/session_basics.html)
|
||||
- [FastAPI dependencies with yield](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/)
|
||||
|
||||
Status: adopted
|
||||
Decision level: mandatory
|
||||
Applies to: api-runtime, workers, tests
|
||||
Last reviewed: 2026-06-17
|
||||
??? abstract "Decision metadata"
|
||||
- Status: adopted
|
||||
- Decision level: mandatory
|
||||
- Applies to: api-runtime, workers, tests
|
||||
- Last reviewed: 2026-06-17
|
||||
|
||||
---
|
||||
|
||||
@@ -49,14 +50,14 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
|
||||
def get_session_factory(request: Request) -> async_sessionmaker[AsyncSession]:
|
||||
return request.app.state.session_factory
|
||||
return request.app.state.session_factory
|
||||
|
||||
|
||||
async def get_db_session(
|
||||
session_factory: async_sessionmaker[AsyncSession] = Depends(get_session_factory),
|
||||
session_factory: async_sessionmaker[AsyncSession] = Depends(get_session_factory),
|
||||
) -> AsyncIterator[AsyncSession]:
|
||||
async with session_factory() as session:
|
||||
yield session
|
||||
async with session_factory() as session:
|
||||
yield session
|
||||
```
|
||||
|
||||
Route usage:
|
||||
@@ -70,10 +71,10 @@ router = APIRouter()
|
||||
|
||||
@router.post("/items")
|
||||
async def create_item(session: AsyncSession = Depends(get_db_session)) -> dict:
|
||||
async with session.begin():
|
||||
# write operations here
|
||||
...
|
||||
return {"status": "ok"}
|
||||
async with session.begin():
|
||||
# write operations here
|
||||
...
|
||||
return {"status": "ok"}
|
||||
```
|
||||
|
||||
---
|
||||
@@ -86,9 +87,9 @@ Typical session factory setup:
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
|
||||
|
||||
session_factory = async_sessionmaker(
|
||||
engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# <Concept Title>
|
||||
|
||||
Source:
|
||||
- <primary source url>
|
||||
- <secondary source url>
|
||||
!!! info "Primary sources"
|
||||
- Primary source: `<primary source URL>`
|
||||
- Secondary source: `<secondary source URL>`
|
||||
|
||||
Status: draft|adopted|deprecated
|
||||
Decision level: advisory|mandatory
|
||||
Applies to: api-runtime|workers|tests
|
||||
Last reviewed: YYYY-MM-DD
|
||||
??? abstract "Decision metadata"
|
||||
- Status: draft|adopted|deprecated
|
||||
- Decision level: advisory|mandatory
|
||||
- Applies to: api-runtime|workers|tests
|
||||
- Last reviewed: YYYY-MM-DD
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# Async Transaction Boundaries
|
||||
|
||||
Source:
|
||||
- https://docs.sqlalchemy.org/en/21/orm/session_transaction.html
|
||||
- https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html
|
||||
- https://docs.sqlalchemy.org/en/21/core/connections.html
|
||||
!!! info "Primary sources"
|
||||
- [SQLAlchemy transactions](https://docs.sqlalchemy.org/en/21/orm/session_transaction.html)
|
||||
- [SQLAlchemy asyncio extension](https://docs.sqlalchemy.org/en/21/orm/extensions/asyncio.html)
|
||||
- [SQLAlchemy connections](https://docs.sqlalchemy.org/en/21/core/connections.html)
|
||||
|
||||
Status: adopted
|
||||
Decision level: mandatory
|
||||
Applies to: api-runtime, workers, tests
|
||||
Last reviewed: 2026-06-17
|
||||
??? abstract "Decision metadata"
|
||||
- Status: adopted
|
||||
- Decision level: mandatory
|
||||
- Applies to: api-runtime, workers, tests
|
||||
- Last reviewed: 2026-06-17
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user