Python Outbox Core
Core abstractions for implementing the Transactional Outbox pattern with Kafka/FastStream
📦 What is this?
This library provides framework-agnostic base classes and interfaces for implementing the Transactional Outbox Pattern, ensuring atomic writes to your database and reliable event publishing.
🎯 Problem Solved
The Dual Write Problem:
- Writing to DB + Publishing to Kafka = Two separate systems
- If app crashes between the two → Event lost
- If Kafka is down → Event lost
- Result: Inconsistent state
The Outbox Solution:
- Store events in outbox table (same DB transaction as your domain changes)
- Background worker publishes events to Kafka asynchronously
- ✅ Atomic: DB writes + event storage in single transaction
- ✅ Durable: Events never lost (stored in DB)
- ✅ Reliable: Publishing retries handled separately
🔀 When to Use This Library?
Use IOutboxEvent (this library) for:
- 🌐 Cross-service communication (other microservices need to react)
- 🌐 External integrations (analytics, audit services, third-party)
- 🌐 Event-driven architecture (Kafka, message brokers)
- 🌐 Guaranteed delivery (at-least-once semantics)
Do NOT use for:
- 🔷 In-process events (use
BaseDomainEventfrompython-domain-primitives) - 🔷 Same service side effects (send email, update cache within same service)
- 🔷 Direct function calls (no message broker needed)
Event Type Decision Tree
Need to publish an event?
│
├─ Same service only?
│ └─ Use BaseDomainEvent (python-domain-primitives)
│ Examples: Send email, log activity, update cache
│
└─ Other services/external?
└─ Use IOutboxEvent (python-outbox-core) ⭐ THIS LIBRARY
Examples: Notify microservices, analytics, audit
Related Libraries:
- 🔷
python-domain-primitives- For internal domain events (BaseDomainEvent) - 🌐
python-outbox-core- For external integration events (IOutboxEvent) ⭐ YOU ARE HERE - 🔧
python-outbox-fastapi- FastAPI lifespan helpers - 🔧
python-outbox-celery- Celery background workers - 🔧
python-outbox-faststream- Kafka/FastStream publishers
🏗️ What's Included
Core Abstractions
from python_outbox_core import IOutboxEvent, IOutboxRepository, OutboxPublisherBase
# 1. Event Interface
class MyDomainEvent(IOutboxEvent):
"""Your domain events implement this interface."""
pass
# 2. Repository Interface
class MyOutboxRepo(IOutboxRepository):
"""Your SQLAlchemy repository implements this."""
pass
# 3. Publisher Base Class
class MyOutboxWorker(OutboxPublisherBase):
"""Your background worker extends this."""
pass
📚 Components
| Component | Purpose | LOC |
|---|---|---|
IOutboxEvent |
Base interface for outbox events with metadata | ~20 |
IOutboxRepository |
Repository contract for outbox persistence | ~25 |
OutboxPublisherBase |
Reusable publishing logic for workers | ~40 |
NOTE: No custom serializer! Use Pydantic's model_dump_json() & FastStream's auto-serialization.
💡 RECOMMENDED: FastStream (by ag2ai) - cutting-edge event-driven framework, ideal for startups. Or implement custom serializers as needed.
🔧 Tech Stack Integration
- SQLAlchemy - For ORM models and async sessions
- Kafka - Event streaming platform
- FastStream - High-level Kafka abstraction
- Kong Events Gateway - API gateway for event routing
📖 Usage Example
from python_outbox_core import IOutboxEvent, IOutboxRepository, OutboxPublisherBase
from pydantic import BaseModel, Field
from datetime import datetime
from uuid import UUID, uuid4
# 1. Define your domain event
class InviteCreatedEvent(BaseModel, IOutboxEvent):
event_id: UUID = Field(default_factory=uuid4)
event_type: str = "invite.created"
aggregate_id: str
occurred_at: datetime = Field(default_factory=datetime.utcnow)
# Domain-specific payload
email: str
role: str
def to_message(self) -> dict:
return self.model_dump(mode='json')
# 2. Implement repository (your SQLAlchemy code)
class OutboxRepository(IOutboxRepository):
def __init__(self, session: AsyncSession):
self.session = session
async def add_event(self, event: IOutboxEvent) -> None:
outbox_record = OutboxEventModel(**event.to_message())
self.session.add(outbox_record)
# ... implement other methods
# 3. Create background worker
class KafkaOutboxWorker(OutboxPublisherBase):
async def schedule_publishing(self) -> None:
while True:
published = await self.publish_batch(limit=100)
await asyncio.sleep(5) # Poll every 5 seconds
🚀 Installation
cd C:\coding\gridflow
pip install -e ./python-web-toolkit/packages/python-outbox-core
🔗 Related Libraries
sqlalchemy-async-repositories- Base repository patternspython-infrastructure-exceptions- Infrastructure errorspython-structlog-config- Structured logging with OTel
📄 License
MIT
🤝 Contributing
This is part of the GridFlow python-web-toolkit monorepo. Follow the 100-line file limit rule.
Metadata
Release files for python-outbox-core 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| python_outbox_core-0.1.0.tar.gz | 17.5 kB | Without provenance | Details for python_outbox_core-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| python_outbox_core-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for python_outbox_core-0.1.0-py3-none-any.whl |
Total release size: 35.8 kB
Release files / python_outbox_core-0.1.0.tar.gz
| Download URL | python_outbox_core-0.1.0.tar.gz |
|---|---|
| Size | 17.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
80e54b4f3381e847abec7fc202868402f5a82c538d09448926f9f454d1f69359
|
|
BLAKE2b-256 checksum How to use checksums |
bc2f9436f27bfa9c28bd202816eef5d66f8cb78ceab6cdd13022b525a72e100a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|
Release files / python_outbox_core-0.1.0-py3-none-any.whl
| Download URL | python_outbox_core-0.1.0-py3-none-any.whl |
|---|---|
| Size | 18.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a2310d54fab48deb93e3192c0fabe422f362a30dbbf7fba3664578e90fd6bf42
|
|
BLAKE2b-256 checksum How to use checksums |
65646d3747ea269ebcc98435b8ea70536f6a9225bd4af374c6b281eda0fc9ac6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.11
|
Security for python-outbox-core 0.1.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.