formatting

This commit is contained in:
John Lancaster
2026-06-19 01:29:05 -05:00
parent 964cd6f76d
commit 3347443ca9
27 changed files with 275 additions and 238 deletions
@@ -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
---