From 5ba831f3e0b72f2cf5cf8d9deb3455ee5e9f1d7e Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 17 Oct 2026 14:44:23 +0300 Subject: [PATCH 1/2] ci: test on PostgreSQL 13 and document it as the minimum --- .github/workflows/_checks.yml | 35 +++++++++++++++++++++++++++++++ docs/introduction/installation.md | 8 +++---- docs/operations/alembic.md | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/.github/workflows/_checks.yml b/.github/workflows/_checks.yml index 0bc27fc..1b92ced 100644 --- a/.github/workflows/_checks.yml +++ b/.github/workflows/_checks.yml @@ -88,6 +88,41 @@ jobs: PYTHONUNBUFFERED: 1 POSTGRES_DSN: postgresql+asyncpg://outbox:outbox@127.0.0.1:5432/outbox + pytest-pg13: + # PostgreSQL 13 is the documented floor: outbox_autovacuum_ddl sets the insert-triggered + # reloptions that 13 introduced. One interpreter is enough, since this leg asks about the + # server, and --no-cov keeps the coverage gate on the main `pytest` matrix. + runs-on: ubuntu-latest + services: + postgres: + image: postgres:13 + env: + POSTGRES_USER: outbox + POSTGRES_PASSWORD: outbox + POSTGRES_DB: outbox + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U outbox" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v6 + - uses: extractions/setup-just@v4 + - uses: astral-sh/setup-uv@v8.2.0 + with: + enable-cache: true + cache-dependency-glob: "**/pyproject.toml" + - run: uv python install 3.13 + - run: uv python pin 3.13 + - run: just install + - run: uv run --no-sync pytest . --no-cov + env: + PYTHONDONTWRITEBYTECODE: 1 + PYTHONUNBUFFERED: 1 + POSTGRES_DSN: postgresql+asyncpg://outbox:outbox@127.0.0.1:5432/outbox + floors: # The declared floors are part of what we ship, and nothing else in CI installs # them: `pytest` and `scheduled-dep-check` both resolve highest. That is how diff --git a/docs/introduction/installation.md b/docs/introduction/installation.md index 43efa63..8beb192 100644 --- a/docs/introduction/installation.md +++ b/docs/introduction/installation.md @@ -23,10 +23,10 @@ ## Requirements - Python 3.11+ -- PostgreSQL 12+. The features used (partial indexes, `FOR UPDATE SKIP - LOCKED`, `make_interval`, `pg_notify`) all predate 12. The examples and - CI run on 17; that is what's exercised, so 17 is the safest choice if - you're starting fresh. +- PostgreSQL 13+. `outbox_autovacuum_ddl` sets the insert-triggered + autovacuum options that 13 introduced; on 12 the `ALTER TABLE` fails. + CI runs the test suite on 13 and on 17. The examples use 17, so that is + the safest choice if you're starting fresh. - A running Postgres instance accessible via SQLAlchemy `AsyncEngine` ## Free-threaded Python diff --git a/docs/operations/alembic.md b/docs/operations/alembic.md index 505b282..dd13ee6 100644 --- a/docs/operations/alembic.md +++ b/docs/operations/alembic.md @@ -209,7 +209,7 @@ def upgrade() -> None: ``` This sets `autovacuum_vacuum_scale_factor = 0` and `autovacuum_vacuum_threshold = -1000` (plus the insert-triggered pair, Postgres 13+). Tune the thresholds for your +1000`, plus the insert-triggered pair, which needs PostgreSQL 13 or later. Tune the thresholds for your message rate, for example `outbox_autovacuum_ddl("outbox", vacuum_threshold=5000, insert_threshold=5000)`. From 13f1f5f8f82e22a1f358ec8cfab014f19e723d1a Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 17 Oct 2026 14:52:21 +0300 Subject: [PATCH 2/2] ci: run the floors job on PostgreSQL 13 instead of a separate job --- .github/workflows/_checks.yml | 39 +++-------------------------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/.github/workflows/_checks.yml b/.github/workflows/_checks.yml index 1b92ced..8129b13 100644 --- a/.github/workflows/_checks.yml +++ b/.github/workflows/_checks.yml @@ -88,41 +88,6 @@ jobs: PYTHONUNBUFFERED: 1 POSTGRES_DSN: postgresql+asyncpg://outbox:outbox@127.0.0.1:5432/outbox - pytest-pg13: - # PostgreSQL 13 is the documented floor: outbox_autovacuum_ddl sets the insert-triggered - # reloptions that 13 introduced. One interpreter is enough, since this leg asks about the - # server, and --no-cov keeps the coverage gate on the main `pytest` matrix. - runs-on: ubuntu-latest - services: - postgres: - image: postgres:13 - env: - POSTGRES_USER: outbox - POSTGRES_PASSWORD: outbox - POSTGRES_DB: outbox - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U outbox" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - steps: - - uses: actions/checkout@v6 - - uses: extractions/setup-just@v4 - - uses: astral-sh/setup-uv@v8.2.0 - with: - enable-cache: true - cache-dependency-glob: "**/pyproject.toml" - - run: uv python install 3.13 - - run: uv python pin 3.13 - - run: just install - - run: uv run --no-sync pytest . --no-cov - env: - PYTHONDONTWRITEBYTECODE: 1 - PYTHONUNBUFFERED: 1 - POSTGRES_DSN: postgresql+asyncpg://outbox:outbox@127.0.0.1:5432/outbox - floors: # The declared floors are part of what we ship, and nothing else in CI installs # them: `pytest` and `scheduled-dep-check` both resolve highest. That is how @@ -132,6 +97,8 @@ jobs: # the same versions can still disagree on whether those versions install. # 3.14t is out: the dev group's `faststream[kafka]` pulls aiokafka, which ships no cp314t # wheel, so under --no-build this leg would measure upstream's gap rather than a floor. + # PostgreSQL 13 is the server floor: outbox_autovacuum_ddl sets the insert-triggered + # reloptions that 13 introduced. if: github.event_name != 'schedule' runs-on: ubuntu-latest strategy: @@ -144,7 +111,7 @@ jobs: - "3.14" services: postgres: - image: postgres:17 + image: postgres:13 env: POSTGRES_USER: outbox POSTGRES_PASSWORD: outbox