Skip to main content

Sagaz - Production-Ready Saga Pattern for Python

codecov Tests Python License PyPI

Enterprise-grade distributed transaction orchestration with exactly-once semantics.


Features

Core Saga Pattern

  • Sequential & Parallel (DAG) execution - Optimize throughput with dependency graphs
  • Automatic compensation - Rollback on failures with transaction safety
  • Three failure strategies - FAIL_FAST, WAIT_ALL, FAIL_FAST_WITH_GRACE
  • Retry logic - Exponential backoff with configurable limits
  • Timeout protection - Per-step and global timeouts
  • Idempotency support - Safe retries and recovery

Transactional Outbox Pattern

  • Exactly-once delivery - Transactional event publishing
  • Optimistic sending - 10x latency improvement (<10ms)
  • Consumer inbox - Exactly-once processing guarantee
  • Multiple brokers - Redis Streams, Kafka, RabbitMQ, or in-memory
  • Dead letter queue - Automatic failure handling
  • Worker auto-scaling - Kubernetes HPA support

Configuration & Developer Experience

  • Unified SagaConfig - Single config for storage, broker, observability
  • Environment variables - 12-factor app support via SagaConfig.from_env()
  • Mermaid diagrams - saga.to_mermaid() for flowchart visualization
  • Connected graph validation - Enforces single connected component in DAG sagas
  • Global configuration - Configure once, all sagas inherit
  • Type-safe instances - Real storage/broker instances, not brittle strings

Storage Backends

  • SQLite - File-based persistence for local development and smaller deployments
  • PostgreSQL - Production-grade with ACID guarantees
  • Redis - High-performance storage backend
  • In-Memory - Testing and development

Monitoring & Operations

  • Prometheus metrics - 40+ metrics exposed
  • OpenTelemetry tracing - Distributed tracing support
  • Structured logging - JSON logs with correlation IDs
  • Grafana dashboard - Ready-to-import JSON template
  • Kubernetes manifests - Production-ready deployment
  • Health checks - Liveness and readiness probes
  • Chaos engineering tests - 12 resilience tests validating production readiness

Installation

# Core library (includes the CLI)
pip install sagaz

# With SQLite persistence
pip install "sagaz[sqlite]"

# With PostgreSQL support
pip install "sagaz[postgres]"

# With Redis support
pip install "sagaz[redis]"

# With both PostgreSQL and Redis storage adapters
pip install "sagaz[storage]"

# With Kafka broker
pip install "sagaz[kafka]"

CLI Deployment Scenarios

The CLI is included in the core package; use it for your deployment scenario:

# Local development (Docker Compose)
sagaz init --local
sagaz dev

# Self-hosted/on-premise servers
sagaz init --selfhost

# Kubernetes (cloud-native)  
sagaz init --k8s

# Hybrid (local DB + cloud broker)
sagaz init --hybrid

# Run benchmarks
sagaz benchmark
sagaz benchmark --profile stress

CLI Examples Browser

Explore and run built-in examples directly from the CLI:

# List all available examples
sagaz examples list

# Filter by category
sagaz examples list --category fintech
sagaz examples list -c iot

# Run a specific example
sagaz examples run ecommerce/order_processing
sagaz examples run monitoring

# Interactive selection menu
sagaz examples select
sagaz examples select --category ml

Available Categories:

  • ecommerce - Order processing workflows
  • fintech - Payment & trading systems
  • healthcare - Patient onboarding
  • integrations - FastAPI, Flask, Django integration examples (requires uv pip install uvicorn werkzeug asgiref)
  • iot - Device orchestration, smart grid
  • logistics - Drone delivery
  • ml - Training pipelines, federated learning
  • monitoring - Metrics and observability
  • travel - Booking systems

Quick Start

Sagaz provides a unified Saga class that supports two usage modes. You choose one approach per saga - mixing is not allowed.

Mode 1: Declarative (Decorators)

Best for sagas defined as classes with clear step methods:

from sagaz import Saga, action, compensate

class OrderSaga(Saga):
    saga_name = "order-processing"
    
    @action("reserve_inventory")
    async def reserve_inventory(self, ctx):
        inventory_id = await inventory_service.reserve(ctx["order_id"])
        return {"inventory_id": inventory_id}
    
    @compensate("reserve_inventory")
    async def release_inventory(self, ctx):
        await inventory_service.release(ctx["inventory_id"])
    
    @action("charge_payment", depends_on=["reserve_inventory"])
    async def charge_payment(self, ctx):
        return await payment_service.charge(ctx["amount"])

# Execute saga
saga = OrderSaga()
result = await saga.run({"order_id": "123", "amount": 99.99})

Mode 2: Imperative (add_step)

Best for dynamic sagas or when steps are defined at runtime:

from sagaz import Saga

# Create saga and add steps programmatically
saga = Saga(name="order-processing")

# Method chaining for fluent API
saga.add_step("validate", validate_order)
saga.add_step("reserve", reserve_inventory, release_inventory, depends_on=["validate"])
saga.add_step("charge", charge_payment, refund_payment, depends_on=["reserve"])
saga.add_step("ship", ship_order, depends_on=["charge"])

# Execute
result = await saga.run({"order_id": "123", "amount": 99.99})

Note: You cannot mix both approaches. Once you use decorators, add_step() will raise an error, and vice versa.

Transactional Outbox + Optimistic Sending

from sagaz.outbox import OptimisticPublisher, OutboxWorker
from sagaz.outbox.storage import PostgreSQLOutboxStorage
from sagaz.outbox.brokers import KafkaBroker

# Setup
storage = PostgreSQLOutboxStorage("postgresql://localhost/db")
broker = KafkaBroker(bootstrap_servers="localhost:9092")
publisher = OptimisticPublisher(storage, broker, enabled=True)

# Publish event transactionally
async with db.transaction():
    await saga_storage.save(saga)
    await outbox_storage.insert(event)
    # Transaction committed

# Immediate publish (< 10ms)
await publisher.publish_after_commit(event)
# Falls back to worker if fails

Consumer Inbox (Exactly-Once)

from sagaz.outbox import ConsumerInbox

inbox = ConsumerInbox(storage, consumer_name="order-service")

async def process_order(payload: dict):
    order = await create_order(payload)
    return {"order_id": order.id}

# Exactly-once processing - duplicates automatically skipped
result = await inbox.process_idempotent(
    event_id=msg.headers['message_id'],
    source_topic=msg.topic,
    event_type="OrderCreated",
    payload=msg.value,
    handler=process_order
)

Unified Configuration

Unified Configuration

from sagaz import SagaConfig, configure, create_storage_manager  

# NEW: Unified StorageManager (recommended)
# Manages connection pooling for both saga and outbox storage
manager = create_storage_manager("postgresql://localhost/db")
await manager.initialize()

config = SagaConfig(
    storage_manager=manager,
    broker=KafkaBroker(bootstrap_servers="localhost:9092"),
    metrics=True,
)
configure(config)

# OR: Traditional separate configuration
config = SagaConfig(
    storage=PostgreSQLSagaStorage("postgresql://localhost/db"),
    broker=KafkaBroker(...),
    metrics=True,
)
configure(config)

# Or from environment variables (12-factor app)
config = SagaConfig.from_env()  # Reads SAGAZ_STORAGE_URL, etc.

Mermaid Diagram Visualization

from sagaz import Saga, action, compensate

class OrderSaga(Saga):
    saga_name = "order"
    
    @action("reserve")
    async def reserve(self, ctx): return {}
    
    @compensate("reserve")
    async def release(self, ctx): pass
    
    @action("charge", depends_on=["reserve"])
    async def charge(self, ctx): return {}
    
    @compensate("charge")
    async def refund(self, ctx): pass

saga = OrderSaga()

# Generate Mermaid diagram with state markers
print(saga.to_mermaid())

# Visualize specific execution from storage
diagram = await saga.to_mermaid_with_execution(
    saga_id="abc-123",
    storage=PostgreSQLSagaStorage(...)
)

Output: State machine diagram with START/SUCCESS/ROLLED_BACK markers, color-coded paths (green=success, amber=compensation, red=failure), and execution trail highlighting.


Kubernetes Deployment

# One-command deployment
kubectl create namespace sagaz
kubectl apply -f k8s/

# Deployed components:
# - PostgreSQL StatefulSet (20Gi persistent storage)
# - Outbox Worker Deployment (3-10 replicas with HPA)
# - Prometheus ServiceMonitor + 8 Alert Rules
# - Database Migration Job

Features:

  • Auto-scaling based on pending events
  • Zero-downtime rolling updates
  • Built-in health checks
  • Production security (non-root, read-only fs)
  • Complete monitoring stack

See k8s/README.md for detailed deployment guide.


Monitoring

Prometheus Metrics

# Saga metrics
saga_execution_total{status}
saga_execution_duration_seconds
saga_step_duration_seconds{step_name}

# Outbox metrics
outbox_pending_events_total
outbox_published_events_total
outbox_optimistic_send_success_total
consumer_inbox_duplicates_total

Grafana Dashboard

Ready-to-import dashboard template at grafana/sagaz-dashboard.json.

Grafana Alerts

  • OutboxHighLag - >5000 pending events for 10min
  • OutboxWorkerDown - No workers running
  • OutboxHighErrorRate - >1% publish failures
  • OptimisticSendHighFailureRate - >10% optimistic failures

Chaos Engineering

Production readiness validated through deliberate failure injection.

The library includes comprehensive chaos engineering tests that verify system resilience:

Test Categories

  • Worker Crash Recovery - Workers can recover from crashes, no data loss
  • Database Connection Loss - Graceful handling of DB failures with retry
  • Broker Downtime - Messages not lost when broker unavailable
  • Network Partitions - No duplicate processing under split-brain
  • Concurrent Failures - System recovers from multiple simultaneous failures
  • Data Consistency - Exactly-once guarantees maintained under chaos

Run Chaos Tests

# Run all chaos engineering tests
pytest tests/test_chaos_engineering.py -v -m chaos

# Test specific failure scenario
pytest tests/test_chaos_engineering.py::TestWorkerCrashRecovery -v

Key Findings:

  • No data loss even with 30% random failure rate
  • Exactly-once processing with 5 concurrent workers
  • Graceful handling of 50 events under extreme load
  • Automatic recovery with exponential backoff

See docs/CHAOS_ENGINEERING.md for detailed chaos test documentation.


Documentation

Topic Link
Documentation Index docs/DOCUMENTATION_INDEX.md
Configuration Guide docs/guides/configuration.md
DAG Pattern docs/feature_compensation_graph.md
Optimistic Sending docs/optimistic-sending.md
Consumer Inbox docs/consumer-inbox.md
Kubernetes Deploy k8s/README.md
Grafana Dashboards grafana/README.md
Chaos Engineering docs/CHAOS_ENGINEERING.md
Observability Reference docs/observability/OBSERVABILITY_REFERENCE.md
Changelog docs/development/changelog.md

Performance

Operation Latency Notes
Saga execution ~50ms Baseline
Outbox polling ~100ms Baseline
Optimistic publish <10ms 10x faster
Inbox dedup check <1ms Sub-millisecond

Tested on:

  • PostgreSQL 16
  • Kafka 3.x
  • 4 CPU cores, 8GB RAM

Production Stats

  • 96% test coverage (860+ passing tests)
  • Type-safe - Full type hints
  • Zero dependencies - Core features work standalone
  • Well-documented - Comprehensive examples
  • Battle-tested - Production-ready
  • Kubernetes-native - Cloud-ready deployment
  • Mermaid visualization - Auto-generated saga diagrams

Development

# Clone repository
git clone https://github.com/brunolnetto/sagaz.git
cd sagaz

# Install dependencies (using uv)
uv sync --all-extras

# Run tests
uv run pytest

# With coverage
uv run pytest --cov=sagaz --cov-report=html
# Current: 96% coverage

License

MIT License - see LICENSE file for details.


Project Status

Current Version: 1.6.0 (November 2026)

Recent Updates (v1.6.0):

  • Dead Letter Queue - park, replay, and purge failed outbox events, with Prometheus depth metrics
  • SQLite storage - Saga storage and transactional outbox through the optional sagaz[sqlite] extra
  • Storage migration - cross-backend transfer tooling, canonical validation, checksums, and destination-state safeguards
  • Developer workflow - conventional-commit and branch-name validation improvements

Earlier Releases:

  • v1.4.0: Lightweight context streaming, industry examples, and saga replay/time-travel
  • v1.3.0: Pivot steps, event triggers, dry-run mode, CLI, and framework integration
  • v1.2.0: Unified storage layer and compensation result passing
  • Consumer inbox pattern (exactly-once processing)
  • Kubernetes manifests (production deployment)
  • 96% test coverage with 860+ tests

See docs/ROADMAP.md for roadmap.


Need Help?

  • Read the docs
  • Report issues
  • Join discussions
  • Contact maintainers

Built for distributed systems

Metadata

Release files for sagaz 1.7.2

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

Source distribution (sdist)

Source distribution for sagaz 1.7.2
File Size Uploaded Provenance Actions
sagaz-1.7.2.tar.gz 401.7 kB Without provenance Details for sagaz-1.7.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sagaz 1.7.2
File Interpreter ABI Platform Actions
sagaz-1.7.2-py3-none-any.whl Python 3 none any Details for sagaz-1.7.2-py3-none-any.whl

Total release size: 944.0 kB

Release files / sagaz-1.7.2.tar.gz

Download URL sagaz-1.7.2.tar.gz
Size 401.7 kB
Tags Source
SHA-256 checksum
How to use checksums
248a3aad34e3084f5eb3b3beb4c5ba4e1cb27dafad10476050031db3f952ebe0
BLAKE2b-256 checksum
How to use checksums
c6b3de07b10a6515c06369756a530f7e218610ab2b1772719e0d6cf36ac96057
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.9

Release files / sagaz-1.7.2-py3-none-any.whl

Download URL sagaz-1.7.2-py3-none-any.whl
Size 542.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4564f4ad44d7c66d8c30530ec90d71808e65010039b7c836cc9e54af8bd6926e
BLAKE2b-256 checksum
How to use checksums
d27e1058ef49827ce24f67de05a74de564668650ad80ee058cbeffb34b5c6fd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.9

Security for sagaz 1.7.2

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.

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