Skip to content
Merged
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ repository.

`db-retry` is a library of retry, connection, and transaction helpers for PostgreSQL applications
built on SQLAlchemy's asyncio extension and asyncpg; [`CONTEXT.md`](CONTEXT.md) opens with what it
does and owns the vocabulary — read it before naming a concept in code, a test name, or an issue
does and owns the vocabulary. Read it before naming a concept in code, a test name, or an issue
title. The words most easily got wrong here are the ones this package shares with PostgreSQL: what
"retriable" covers, what a "retry" counts, and what "primary" does not mean.

## Commands

`just` (task runner) and `uv` (package manager). The [`justfile`](justfile) is the source of truth —
`just --list`, or read it. The one thing it does not say: `just test` is Docker-only, so without a
`just` (task runner) and `uv` (package manager). The [`justfile`](justfile) is the source of truth:
run `just --list`, or read it. The one thing it does not say: `just test` is Docker-only, so without a
Docker daemon, point `DB_DSN` at any reachable PostgreSQL and run `uv run pytest` directly.

## Architecture
Expand Down
8 changes: 4 additions & 4 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@ package uses it.
A PostgreSQL failure that can be re-run unchanged, because it says nothing about the request being
wrong: a serialization failure (`40001`) or a lost connection (class `08`, or a `DBAPIError`
SQLAlchemy marked `connection_invalidated`). `RETRIABLE_ASYNCPG_ERRORS` and that flag are the whole
of it — an error outside them is not retriable, however temporary it looks.
_Avoid_: transient error — it describes how long the failure lasts, not whether repeating the work
of it: an error outside them is not retriable, however temporary it looks.
_Avoid_: transient error. It describes how long the failure lasts, not whether repeating the work
is safe, and the two come apart: `StatementCompletionUnknownError` (`40003`) is as short-lived as
`40001` and must never be retried.

**Attempt**:
One call of the wrapped coroutine. `postgres_retry(retries=N)` bounds *attempts*, not retries — `N`
One call of the wrapped coroutine. `postgres_retry(retries=N)` bounds *attempts*, not retries: `N`
caps the calls of the body, so `retries=1` runs the body once and never re-runs it,
and the `DB_RETRY_RETRIES_NUMBER` default of `3` allows two re-runs.
_Avoid_: retry, as a count. The knob is spelled `retries` for callers and cannot be renamed without
breaking them, but every number in this package counts attempts.

**Primary host**:
The host a connection's first connect attempt is aimed at — which, for a multi-host DSN, is
The host a connection's first connect attempt is aimed at. For a multi-host DSN that is
*every* host, in an order shuffled afresh for each connection, handed to asyncpg to walk itself.
"Primary" is a position in the two-stage connect (one bulk attempt, then host-by-host through
`failover`), not a PostgreSQL replication role; replication role is `target_session_attrs`, where
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,4 +227,4 @@ export DB_RETRY_RETRIES_NUMBER=5
## Part of `modern-python`

Browse the full list of templates and libraries in
[`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index.
[`modern-python`](https://github.com/modern-python); see the org profile for the categorized index.
Loading