Skip to content

Add a Postgres broker - #1

Closed
bigjools wants to merge 1 commit into
masterfrom
cursor/postgres-broker-plan-e7fb
Closed

bigjools wants to merge 1 commit into
masterfrom
cursor/postgres-broker-plan-e7fb

Conversation

@bigjools

@bigjools bigjools commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds PostgresBroker. Jobs live in Postgres. Application code can insert a job in its own transaction, so the job and the local rows commit together or roll back together.

  • pip install spinach[postgres] installs psycopg 3. The DSN comes from the application.
  • Queues, future jobs, periodic tasks, concurrency limits, namespaces, broker keepalive, and re-queue after a broker dies.
  • Engine.join_transaction schedules on the caller's open transaction when the broker sets supports_join_transaction. PostgresBroker inserts the job rows on that connection and does not commit it. Workers see the job when the caller commits. Rollback removes both.
  • A broker that does not support joining a transaction raises RuntimeError. A task parameter named connection is still passed to the task.
  • require_ssl defaults to True. The session must use TLS with sslmode=verify-full. sslmode=require is rejected because the server certificate is not verified. Production DSNs use SCRAM-SHA-256 and sslrootcert. Check the server certificate with openssl x509 -text -noout before trusting it. Tests pass require_ssl=False because the test server uses trust authentication.
  • join_transaction compares pg_control_system().system_identifier, current_database(), and the OIDs of spinach_queue_job and spinach_future_job. The same cluster, database, and tables match whatever host string or socket was used. A search_path that finds a different copy is rejected.
  • A fresh enqueue inserts the job and notifies. It does not delete running rows, so an application role with INSERT on the queue and future tables and USAGE on the position sequence can schedule. A failure requeue still clears that job's running row and frees its concurrency slot.
  • Startup resolves each Spinach table with to_regclass and checks column types, nullability, primary keys, the position sequence default, the idempotency now() default, and spinach_schema version 1. A stub earlier on search_path is rejected. A discarded job from a dead broker releases its concurrency slot. An empty task list clears concurrency rows.
  • doc/user/postgres.rst explains how to use, deploy, and control the broker. doc/hacking/postgres-broker.rst describes the implementation.

Test plan

  • pytest — 160 passed, including an insert-only role, a hidden search_path, missing column defaults, and a failure requeue clearing the running row.
  • tests/functional/test_concurrency.py — two workers and max_concurrency=1 on memory, Redis, and Postgres.
  • pycodestyle --ignore=E252,W503,W504 spinach tests
  • CI on Python 3.8–3.13 with the Postgres service. PyPy skips the Postgres extra.
Open in Web Open in Cursor 

@coveralls

coveralls commented Oct 7, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 37736583607

Coverage decreased (-0.8%) to 90.132%

Details

  • Coverage decreased (-0.8%) from the base build.
  • Patch coverage: 66 uncovered changes across 2 files (470 of 536 lines covered, 87.69%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
spinach/brokers/postgres.py 514 449 87.35%
spinach/contrib/flask_spinach.py 3 2 66.67%
Total (4 files) 536 470 87.69%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1814
Covered Lines: 1635
Line Coverage: 90.13%
Coverage Strength: 6.1 hits per line

💛 - Coveralls

@cursor cursor Bot changed the title Plan a Postgres broker Add a Postgres broker proof of concept Oct 7, 2026
@cursor cursor Bot changed the title Add a Postgres broker proof of concept Add a Postgres broker Oct 7, 2026
Jobs live in Postgres. Engine.join_transaction inserts them on the
caller's open transaction, so application rows and job rows commit or
roll back together.

PostgresBroker runs queues, future jobs, periodic tasks, concurrency
limits, namespaces, broker keepalive, and recovery after a broker dies.
A joined connection must be the same cluster, database, and Spinach
tables as the broker. Startup checks schema version 1, column shape,
the position and idempotency defaults, and sslmode=verify-full.

Co-authored-by: Julian Edwards <bigjools@gmail.com>
@cursor
cursor Bot force-pushed the cursor/postgres-broker-plan-e7fb branch from 84d44df to 4c2c889 Compare October 8, 2026 06:15
@bigjools bigjools closed this Oct 8, 2026
@bigjools

bigjools commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

See NicolasLM#51

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants