Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pip install db-retry

### 1. Database operations with automatic retry

Retry a coroutine on serialization failures and lost connections. The retried coroutine must open its own transaction with `Transaction`, so that a failed attempt is rolled back before the next one starts. If it reuses a session that is still inside the failed transaction, the next attempt raises `PendingRollbackError` and the retry gives up.
Retry a coroutine on serialization failures and lost connections. Either error ends the whole Postgres transaction, so the retried coroutine has to own its transaction from start to finish: open it with `Transaction`, as below, or work on a fresh session it creates itself. A coroutine that runs on a session someone else began cannot be retried. Postgres has already discarded the statements that ran before it, and SQLAlchemy refuses the next attempt with `PendingRollbackError` instead of committing part of the work.

```python
import asyncio
Expand Down Expand Up @@ -197,7 +197,7 @@ export DB_RETRY_RETRIES_NUMBER=5
- `@postgres_retry` - Decorator for async functions that should retry on database errors (total attempts, first call plus retries, from `DB_RETRY_RETRIES_NUMBER`)
- `@postgres_retry(retries=N)` - Override the total attempts (first call plus retries) per callsite
- Retries a serialization failure (`40001`), a connection error (class `08`), and any `DBAPIError` that SQLAlchemy marks with `connection_invalidated`. The last one covers asyncpg's `InterfaceError: connection is closed` on a pooled connection that died while idle, which is what `pool_pre_ping=True` otherwise catches
- The retried coroutine must open its own `Transaction`; a retry on a session left in a failed transaction raises `PendingRollbackError`
- The retried coroutine must own its whole transaction, through `Transaction` or a fresh session; on a session another caller began, the next attempt raises `PendingRollbackError`
- Retries also fire when the retriable `asyncpg` error is wrapped by [`advanced-alchemy`](https://github.com/litestar-org/advanced-alchemy)'s `wrap_sqlalchemy_exception()` (i.e. surfaced as `RepositoryError` / `IntegrityError`); the handler walks the `__cause__` / `__context__` chain.

### Connection utilities
Expand Down
Loading