diff --git a/AGENTS.md b/AGENTS.md index dc28ad6..8f53c38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 diff --git a/CONTEXT.md b/CONTEXT.md index edfa462..d09e5ad 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -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 diff --git a/README.md b/README.md index 1451e51..ece2658 100644 --- a/README.md +++ b/README.md @@ -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.