A reliable, lightweight, framework-agnostic Transactional Outbox pattern implementation for Python (FastAPI, Flask, etc.).
Project description
Outbox Pattern SDK (outbox-pattern)
A lightweight, reliable, framework-agnostic implementation of the Transactional Outbox Pattern in Python. Built to work seamlessly with FastAPI (Async), Flask (Sync), or any custom Python application.
Key Features
- 🔄 Transactional Outbox Pattern: Ensures event publication consistency by storing outbox events atomically before dispatching.
- 🚀 Framework Agnostic: Native support for FastAPI (
asynciolifespan) and Flask (threadingdaemon). - ⚡ Async & Sync Support: Native implementations for both asynchronous (
asyncio) and synchronous (threading) workloads. - 🐇 RabbitMQ Integration: Built-in publishers for
aio-pika(async) andpika(sync). - 🍃 MongoDB Integration: Outbox repositories powered by
beanie(async) andpymongo(sync). - 📊 Telemetry & Observability: Integrated provider for Pydantic Logfire with structured logs and dead-letter event tracing.
- 🛡️ Distributed Lock Safety: Prevents race conditions among multiple concurrent worker instances using optimistic lock timeouts.
Installation
Install the base package or specify optional extras depending on your stack:
# Install for FastAPI (Async: Beanie + aio-pika)
pip install "outbox-pattern[async]"
# Install for Flask (Sync: PyMongo + pika)
pip install "outbox-pattern[sync]"
# Install with Telemetry (Logfire)
pip install "outbox-pattern[telemetry]"
# Install all optional dependencies
pip install "outbox-pattern[all]"
Framework Integration Examples
1. FastAPI Integration (Async)
FastAPI applications manage background workers using the lifespan context manager:
from contextlib import asynccontextmanager
from fastapi import FastAPI
from pydantic import BaseModel
from outbox_pattern import OutboxEvent
from outbox_pattern.async_impl import (
AsyncBeanieRepository,
AsyncAioPikaPublisher,
AsyncOutboxWorker,
)
# Repositories & Workers
repository = AsyncBeanieRepository()
publisher = AsyncAioPikaPublisher(broker_url="amqp://guest:guest@localhost:5672/")
worker = AsyncOutboxWorker(repository=repository, publisher=publisher, poll_interval=3)
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Start the Outbox worker task
await worker.start()
yield
# Shutdown: Stop worker gracefully
await worker.stop()
app = FastAPI(title="My FastAPI Microservice", lifespan=lifespan)
class CreateUserDTO(BaseModel):
user_id: str
email: str
@app.post("/users")
async def create_user(dto: CreateUserDTO):
# 1. Save user inside main DB transaction...
# 2. Save Outbox Event atomically
event = OutboxEvent(
tenant="tenant_default",
topic="user.registered",
payload=dto.model_dump(),
)
await repository.save_event(event)
return {"status": "user_created", "user_id": dto.user_id}
2. Flask Integration (Sync)
Flask applications use daemon background threads for outbox polling:
from flask import Flask, request, jsonify
from pymongo import MongoClient
from outbox_pattern import OutboxEvent
from outbox_pattern.sync_impl import (
SyncPyMongoRepository,
SyncPikaPublisher,
SyncOutboxWorker,
)
app = Flask(__name__)
# Initialize MongoDB & RabbitMQ
mongo_client = MongoClient("mongodb://localhost:27017/")
db = mongo_client["my_flask_app"]
repository = SyncPyMongoRepository(collection=db["outbox_events"])
publisher = SyncPikaPublisher(broker_url="amqp://guest:guest@localhost:5672/")
# Start Outbox worker in a background daemon thread
worker = SyncOutboxWorker(repository=repository, publisher=publisher, poll_interval=5)
worker.start()
@app.route("/orders", methods=["POST"])
def create_order():
data = request.json
# 1. Save order in MongoDB...
# 2. Record Outbox Event
event = OutboxEvent(
tenant=data.get("tenant", "default"),
topic="order.created",
payload=data,
)
repository.save_event(event)
return jsonify({"message": "Order created successfully"}), 201
Observability & Telemetry
Enable Pydantic Logfire telemetry to trace event publishing lifecycle and dead-letter queues:
from outbox_pattern.telemetry import LogfireTelemetryProvider
telemetry = LogfireTelemetryProvider()
worker = AsyncOutboxWorker(
repository=repository,
publisher=publisher,
telemetry=telemetry,
)
Configuration
Environment variables can be set to override default behavior:
| Environment Variable | Default | Description |
|---|---|---|
OUTBOX_MAX_RETRIES |
3 |
Maximum processing attempts before marking an event as failed. |
OUTBOX_BATCH_SIZE |
100 |
Number of events acquired per polling loop iteration. |
OUTBOX_LOCK_TIMEOUT_SECONDS |
300 |
Lock expiration time (in seconds) for stale workers. |
License
This project is licensed under the terms of the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file outbox_pattern-0.1.2.tar.gz.
File metadata
- Download URL: outbox_pattern-0.1.2.tar.gz
- Upload date:
- Size: 8.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ca4005d71be91cb8897a14dfabe2d0a5f62f81c2d4fbf8a36233d2cc40f94a9
|
|
| MD5 |
6c109ce448c47045a6dc5bc9f7470ab5
|
|
| BLAKE2b-256 |
29e9533047e28a383d8856b4c42cb9b6284afc5d73aa8eec386abf2fa2255c11
|
Provenance
The following attestation bundles were made for outbox_pattern-0.1.2.tar.gz:
Publisher:
publish.yml on JohnatanPalacios/outbox_pattern
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
outbox_pattern-0.1.2.tar.gz -
Subject digest:
6ca4005d71be91cb8897a14dfabe2d0a5f62f81c2d4fbf8a36233d2cc40f94a9 - Sigstore transparency entry: 2218652949
- Sigstore integration time:
-
Permalink:
JohnatanPalacios/outbox_pattern@da99ff04f1f844de0275513005c9c3a7e16b4c83 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/JohnatanPalacios
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@da99ff04f1f844de0275513005c9c3a7e16b4c83 -
Trigger Event:
push
-
Statement type:
File details
Details for the file outbox_pattern-0.1.2-py3-none-any.whl.
File metadata
- Download URL: outbox_pattern-0.1.2-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e929ffd0bc424c013f5eabf151b2aa96ed76215e32db6e1468d29d44d1d294cb
|
|
| MD5 |
ca02ac67f9ad112152c49d8336dac962
|
|
| BLAKE2b-256 |
6226fcdbf20e57ff659eae58b7ccf06fc56500b272719d70b5da9e9c9b2d5015
|
Provenance
The following attestation bundles were made for outbox_pattern-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on JohnatanPalacios/outbox_pattern
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
outbox_pattern-0.1.2-py3-none-any.whl -
Subject digest:
e929ffd0bc424c013f5eabf151b2aa96ed76215e32db6e1468d29d44d1d294cb - Sigstore transparency entry: 2218653291
- Sigstore integration time:
-
Permalink:
JohnatanPalacios/outbox_pattern@da99ff04f1f844de0275513005c9c3a7e16b4c83 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/JohnatanPalacios
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@da99ff04f1f844de0275513005c9c3a7e16b4c83 -
Trigger Event:
push
-
Statement type: