You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+
## Commands
6
+
7
+
```bash
8
+
just install # uv lock --upgrade && uv sync
9
+
just lint # ruff format + eof-fixer (auto-fix)
10
+
just lint-ci # ruff check only (no fixes)
11
+
just build # build docker image
12
+
just test# run pytest inside docker (requires postgres)
13
+
just # install lint build test (full pipeline)
14
+
```
15
+
16
+
To run tests locally without Docker, set `DB_DSN` and run:
17
+
```bash
18
+
uv run pytest
19
+
uv run pytest tests/test_retry.py::test_postgres_retry # single test
20
+
```
21
+
22
+
The CI `DB_DSN` format: `postgresql+asyncpg://postgres:postgres@localhost:5432/postgres`
23
+
24
+
## Architecture
25
+
26
+
The package (`db_retry/`) exposes five public symbols via `__init__.py`:
27
+
28
+
-**`postgres_retry`** (`retry.py`) — async tenacity decorator that retries on `asyncpg.SerializationError` (40001) and `asyncpg.PostgresConnectionError` (08000/08003). Walks the exception chain via `DBAPIError.orig.__cause__` to distinguish retriable errors from others like `StatementCompletionUnknownError` (40002). Supports bare `@postgres_retry` (uses default) and `@postgres_retry(retries=N)` for per-callsite override.
29
+
30
+
-**`build_connection_factory`** (`connections.py`) — returns an async callable suitable for SQLAlchemy's `async_engine_from_config`. Handles multi-host DSNs by randomizing host order (load balancing) and attempting all hosts on timeout before raising `TargetServerAttributeNotMatched`.
31
+
32
+
-**`build_db_dsn`** / **`is_dsn_multihost`** (`dsn.py`) — parse and construct `sqlalchemy.URL` objects. Multi-host DSNs encode additional hosts in query parameters. Existing `target_session_attrs` in the DSN is preserved (not overwritten).
33
+
34
+
-**`Transaction`** (`transaction.py`) — frozen dataclass context manager wrapping `AsyncSession`. Supports optional isolation level (e.g., `"SERIALIZABLE"`). Auto-rolls back on `__aexit__` if the session is still in a transaction (i.e. no explicit `.commit()` or `.rollback()` was called). Uses `typing.Self` (no `typing_extensions` dependency).
35
+
36
+
-**`settings.py`** — exposes `get_retries_number()` which reads `DB_RETRY_RETRIES_NUMBER` env var at call time (default: 3), allowing `monkeypatch.setenv` to work in tests.
37
+
38
+
## Linting / Type Checking
39
+
40
+
Ruff is configured with `select = ["ALL"]` plus specific exclusions. Line length is 120. Run `just lint` before committing.
41
+
42
+
Type checking uses `ty` (not mypy). In code, use `ty: ignore` for suppression comments (not `type: ignore`).
Set up resilient database connections with multiple fallback hosts:
@@ -173,21 +181,22 @@ The library can be configured using environment variables:
173
181
174
182
Example:
175
183
```bash
176
-
exportDB_UTILS_RETRIES_NUMBER=5
184
+
exportDB_RETRY_RETRIES_NUMBER=5
177
185
```
178
186
179
187
## API Reference
180
188
181
189
### Retry Decorator
182
-
-`@postgres_retry` - Decorator for async functions that should retry on database errors
190
+
-`@postgres_retry` - Decorator for async functions that should retry on database errors (uses `DB_RETRY_RETRIES_NUMBER`)
191
+
-`@postgres_retry(retries=N)` - Override retry count per callsite
183
192
184
193
### Connection Utilities
185
194
-`build_connection_factory(url, timeout)` - Creates a connection factory for multi-host setups
186
195
-`build_db_dsn(db_dsn, database_name, use_replica=False, drivername="postgresql")` - Builds a DSN with specified parameters
187
196
-`is_dsn_multihost(db_dsn)` - Checks if a DSN contains multiple hosts
188
197
189
198
### Transaction Helper
190
-
-`Transaction(session, isolation_level=None)` - Context manager for simplified transaction handling
199
+
-`Transaction(session, isolation_level=None)` - Context manager for transaction handling; auto-rolls back on exit if no explicit `.commit()` or `.rollback()` was called
0 commit comments