Skip to main content

ballast

Durable backend correctness for single-machine Python — on one SQLite file, with zero dependencies.

The guarantees you'd normally stand up Redis + Postgres + a broker for, delivered against one WAL-mode SQLite database with no server and nothing to operate:

  • Transactional outbox — publish events inside your own transaction, so an event exists if and only if the work that produced it committed. No phantom events, ever.
  • Exactly-once jobs — a background worker runs a handler and marks the job done in the same transaction. A crash rolls back the side effects and the completion together; the job retries. No double-sends, no lost work.
  • Forward-only migrations — a tiny ladder that applies pending steps atomically and refuses to run against a newer database (the install-over-install downgrade guard).
  • Consistent snapshots & restore — VACUUM INTO backups with rotation, and a guarded restore to roll back.
  • OS-keyring secrets — read from the keyring when present, fall back to env vars always.

Built for the deployments that Temporal, Celery, and cloud queues structurally can't serve: desktop apps, on-prem appliances, air-gapped / regulated environments, and CLIs that must be crash-safe on a single box.

CI PyPI Python License


Why

Getting durable execution right on SQLite is a minefield most teams cross badly: writer serialization, BEGIN IMMEDIATE, the WAL pragma regime, the ambiguous-send problem after a crash, phantom events on rollback, idempotency, startup recovery of leased jobs. The usual escape hatch — run Redis/Postgres/Kafka — is impossible to ship to a customer's laptop or an air-gapped box, and absurd overkill for one process.

ballast packages the crash-tested version of all of that behind a small, boring API. It is deliberately dependency-free (standard library only), so there is nothing to audit but the code and it runs anywhere Python does.

Install

pip install ballast.py              # core: zero dependencies
pip install "ballast.py[keyring]"   # optional: OS-keyring-backed secrets

The PyPI distribution is named ballast.py (the plain ballast name belongs to an unrelated load-balancing library). The import name is unaffected: import ballast.

Requires Python 3.10+.

Quick start

from ballast import Database, EventBus, JobWorker, install

db = Database("app.db")
install(db)                                    # create ballast's tables (idempotent)

bus = EventBus()
bus.declare("order.placed")
bus.subscribe("fulfilment", "order.placed",
              lambda conn, e: conn.execute("INSERT INTO orders VALUES (?)", (e.entity_id,)))

with db.transaction() as conn:                 # publish atomically with your own writes
    bus.publish(conn, "order.placed", {"total": 4999}, entity_type="order", entity_id="ord-1")

JobWorker(db, bus=bus).drain()                 # process to quiescence (or .start() in the background)

See examples/quickstart.py and examples/durable_jobs.py.

What you get

Component What it does
Database Correctly-configured connections + a transaction() (BEGIN IMMEDIATE → commit/rollback).
MigrationRunner / Migration Forward-only ladder; atomic per-step; DowngradeError on a newer DB.
snapshot() / restore() VACUUM INTO backups with keep-N rotation; guarded restore.
EventBus Declare topics, publish() inside your transaction, register subscribers.
dispatch_pending / prune_events Advance cursors + enqueue dispatch jobs; prune consumed + aged events.
JobQueue / JobWorker Transactional enqueue/enqueue_unique; single-writer worker; exactly-once, retry+backoff, startup recovery.
SecretStore Keyring-first, env-var fallback secrets.

Design in one paragraph

Everything hangs off two ideas. First, BEGIN IMMEDIATE on every write (ballast runs SQLite in autocommit and issues transactions explicitly) so busy_timeout actually applies and writers queue instead of erroring. Second, the outbox and the job-completion live in the caller's / worker's transaction, so "publish the event" and "do the work" and "mark it done" are atomic with the state change. Ordering is by an AUTOINCREMENT seq (commit order under serialized writers), never by a random id. Full rationale in docs/ARCHITECTURE.md.

Documentation

Scope & non-goals

ballast is single-process, single-machine by design — that constraint is what makes the guarantees cheap and true. It is not a distributed queue, not a multi-writer cluster, and not a replacement for Temporal at scale. If you can run a broker and need multi-node fan-out, use one. If you must ship crash-safe durability inside one binary with no infrastructure, that is exactly what this is for.

License

Apache-2.0.

Metadata

Release files for ballast.py 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ballast.py 0.1.1
File Size Uploaded
ballast_py-0.1.1.tar.gz 28.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ballast.py 0.1.1
File Interpreter ABI Platform
ballast_py-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 56.0 kB

Release files / ballast_py-0.1.1.tar.gz

Download URL ballast_py-0.1.1.tar.gz
Size 28.7 kB
Tags Source
SHA-256 checksum
How to use checksums
51daac704977e4a55c6b41a8bc4c64b387757208aabd44b9d6a116b598a6b470
BLAKE2b-256 checksum
How to use checksums
a63ed7b1bbeb3e54a7e7eaf310a6233279c334e2219c213e8e6724794a5adab5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 7, 2026.

Transparency log

Release files / ballast_py-0.1.1-py3-none-any.whl

Download URL ballast_py-0.1.1-py3-none-any.whl
Size 27.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
188cf57f397c6c873935e01fc2c33b3e8bdd595e4fb2d72429da9c7105489b41
BLAKE2b-256 checksum
How to use checksums
f2c4afc9874d59cc4b3b6e3551df9fe8c92857e01c17034cd252b70bbe3477be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page