Skip to main content

Production-ready Saga pattern with DAG support

Project description

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

  • โœ… PostgreSQL - Production-grade with ACID guarantees
  • โœ… Redis - High-performance caching layer
  • โœ… 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
pip install sagaz

# With PostgreSQL support
pip install sagaz[postgresql]

# With Kafka broker
pip install sagaz[kafka]

# All features
pip install sagaz[all]

๐ŸŽฏ Quick Start

Basic Saga (Declarative API)

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})

Classic API (Imperative)

from sagaz import ClassicSaga

saga = ClassicSaga(name="OrderSaga")

# These run in parallel (no dependencies)
await saga.add_step("check_inventory", check_inventory, compensate_inventory, dependencies=set())
await saga.add_step("validate_address", validate_address, None, dependencies=set())

# This waits for both
await saga.add_step(
    "reserve_items",
    reserve_items,
    release_items,
    dependencies={"check_inventory", "validate_address"}
)

result = await saga.execute()

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 ๐Ÿ†•

from sagaz import SagaConfig, configure

# One config for everything
config = SagaConfig(
    storage=PostgreSQLSagaStorage("postgresql://localhost/db"),
    broker=KafkaBroker(bootstrap_servers="localhost:9092"),
    metrics=True,
    tracing=True,
    logging=True,
)
configure(config)  # All sagas now inherit this config!

# Or from environment variables (12-factor app)
config = SagaConfig.from_env()  # Reads SAGAZ_STORAGE_URL, SAGAZ_BROKER_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, 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
Changelog docs/development/changelog.md

๐Ÿ“ˆ Performance

Operation Latency Improvement
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.0.3 (December 2024)

Recent Updates (v1.0.3):

  • ๐Ÿ†• Mermaid diagram generation with state markers (โ—/โ—Ž)
  • ๐Ÿ†• to_mermaid_with_execution() - Auto-fetch trail from storage
  • ๐Ÿ†• Connected graph validation for DAG sagas
  • ๐Ÿ†• Grafana dashboard template
  • ๐Ÿ†• Unified SagaConfig with environment variable support

v1.0.0-1.0.2:

  • โœ… Optimistic sending pattern (10x latency improvement)
  • โœ… 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 with โค๏ธ for distributed systems

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sagaz-1.0.3.tar.gz (153.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sagaz-1.0.3-py3-none-any.whl (43.9 kB view details)

Uploaded Python 3

File details

Details for the file sagaz-1.0.3.tar.gz.

File metadata

  • Download URL: sagaz-1.0.3.tar.gz
  • Upload date:
  • Size: 153.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.2

File hashes

Hashes for sagaz-1.0.3.tar.gz
Algorithm Hash digest
SHA256 46a78a680f626da5e5e40005ea9a7c3be5a4c4e1d7615711fc5b0d446f85ce52
MD5 0811b661bedebe45e4809889c4f93e21
BLAKE2b-256 20368002b7cbcef02a6c3d21763b36d628d12f3aee442c41c22558073060e7e1

See more details on using hashes here.

File details

Details for the file sagaz-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: sagaz-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 43.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.2

File hashes

Hashes for sagaz-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d07f66f766866cd189831ad146270873da4183d13a6d1ecfdf95cc08655453a2
MD5 b06d0ba79ecf11f639c1454aecadec4c
BLAKE2b-256 0ab76d846ee80761a2516acbef6d5ce21ea28c541c3197285ccfbc234beefd20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page