Skip to main content

Buz

PyPI version Python Support License: MIT Code style: black

Buz is a lightweight, simple, and extensible Python library that provides implementations of Event, Command, and Query buses following CQRS and Event-Driven Architecture patterns.

📋 Table of Contents

✨ Key Features

  • 🚌 Bus Types: Event, Command, and Query buses for clean architecture
  • 🔄 Sync & Async Support: Both synchronous and asynchronous implementations
  • 🔧 Middleware System: Extensible middleware for cross-cutting concerns
  • 📦 Message Brokers: Support for Kafka, RabbitMQ (via Kombu), and in-memory
  • 🔒 Transactional Outbox: Reliable event publishing with transactional guarantees
  • 🎯 Dependency Injection: Built-in locator pattern for handler resolution
  • 📝 Type Safety: Fully typed with mypy support
  • 🪶 Lightweight: Minimal dependencies, maximum flexibility

🚀 Quick Start

Installation

# Basic installation
pip install buz

# With Kafka support
pip install buz[aiokafka]

# With RabbitMQ support
pip install buz[kombu]

# With dependency injection
pip install buz[pypendency]

Basic Usage

Event Bus Example

from dataclasses import dataclass
from buz import Message
from buz.event import Event, BaseSubscriber
from buz.event.sync import SyncEventBus
from buz.locator.sync import InstanceLocator

@dataclass(frozen=True)
class UserCreated(Event):
    user_id: str
    email: str

class EmailSubscriber(BaseSubscriber):
    def consume(self, event: UserCreated) -> None:
        print(f"Sending welcome email to {event.email}")

class AnalyticsSubscriber(BaseSubscriber):
    def consume(self, event: UserCreated) -> None:
        print(f"Tracking user creation: {event.user_id}")

# Setup
locator: InstanceLocator = InstanceLocator()
locator.register(EmailSubscriber())
locator.register(AnalyticsSubscriber())

event_bus = SyncEventBus(locator)

# Usage
event = UserCreated(user_id="123", email="user@example.com")
event_bus.publish(event)

Command Bus Example

from dataclasses import dataclass
from buz.command import Command
from buz.command.synchronous import BaseCommandHandler
from buz.command.synchronous.self_process import SelfProcessCommandBus
from buz.locator.sync import InstanceLocator

@dataclass(frozen=True)
class CreateUser(Command):
    email: str
    name: str

class CreateUserCommandHandler(BaseCommandHandler):
    def handle(self, command: CreateUser) -> None:
        # Business logic here
        print(f"Creating user: {command.name} ({command.email})")

# Setup
locator = InstanceLocator()
locator.register(CreateUserCommandHandler())

command_bus = SelfProcessCommandBus(locator)

# Usage
command = CreateUser(email="user@example.com", name="John Doe")
command_bus.handle(command)

Query Bus Example

from dataclasses import dataclass
from buz.query import Query, QueryResponse
from buz.query.synchronous import BaseQueryHandler
from buz.query.synchronous.self_process import SelfProcessQueryBus
from buz.locator.sync import InstanceLocator

@dataclass(frozen=True)
class GetUser(Query):
    user_id: str

@dataclass(frozen=True)
class User:
    user_id: str
    name: str
    email: str

class GetUserQueryHandler(BaseQueryHandler):
    def handle(self, query: GetUser) -> QueryResponse:
        # Business logic here
        return QueryResponse(
            content=User(
                user_id=query.user_id,
                name="John Doe",
                email="john@example.com"
            )
        )

# Setup
locator = InstanceLocator()
locator.register(GetUserQueryHandler())

query_bus = SelfProcessQueryBus(locator)

# Usage
query = GetUser(user_id="123")
query_response = query_bus.handle(query)
user = query_response.content
print(f"User: {user.name}")

🏗️ Architecture

Buz implements the Command Query Responsibility Segregation (CQRS) pattern with distinct buses:

Event Bus

  • Purpose: Publish domain events and notify multiple subscribers
  • Pattern: Pub/Sub with multiple handlers per event
  • Use Cases: Domain event broadcasting, eventual consistency, integration events

Command Bus

  • Purpose: Execute business operations and commands
  • Pattern: Single handler per command
  • Use Cases: Business logic execution, write operations, state changes

Query Bus

  • Purpose: Retrieve data and execute queries
  • Pattern: Single handler per query with typed responses
  • Use Cases: Data retrieval, read operations, projections

🔧 Advanced Features

Middleware System

Add cross-cutting concerns like logging, validation, and metrics:

from datetime import datetime
from buz.event import Event, Subscriber
from buz.event.middleware import BasePublishMiddleware, BaseConsumeMiddleware
from buz.event.infrastructure.models.execution_context import ExecutionContext

class LoggingPublishMiddleware(BasePublishMiddleware):
    def _before_on_publish(self, event: Event) -> None:
        print(f"Publishing event {event}")

    def _after_on_publish(self, event: Event) -> None:
        return

class MetricsConsumeMiddleware(BaseConsumeMiddleware):
    def __init__(self) -> None:
        self.__consumption_start_time: datetime = datetime.now()

    def _before_on_consume(
        self,
        event: Event,
        subscriber: Subscriber,
        execution_context: ExecutionContext,
    ) -> None:
        self.__consumption_start_time = datetime.now()

    def _after_on_consume(
        self,
        event: Event,
        subscriber: Subscriber,
        execution_context: ExecutionContext,
    ) -> None:
        consumption_time_ms = int((datetime.now() - self.__consumption_start_time).total_seconds() * 1000)
        print(
            f"Subscriber {subscriber.fqn()} consumed event {event.id} successfully in {consumption_time_ms} ms"
        )

# Apply middleware
event_bus = SyncEventBus(
    locator=locator,
    publish_middlewares=[LoggingPublishMiddleware()],
    consume_middlewares=[MetricsConsumeMiddleware()]
)

# Usage
event = UserCreated(user_id="123", email="user@example.com")
event_bus.publish(event)

Transactional Outbox Pattern

Ensure reliable event publishing with database transactions:

from buz.event.transactional_outbox import TransactionalOutboxEventBus

# Configure with your database and event bus
transactional_outbox_bus = TransactionalOutboxEventBus(
    outbox_repository=your_outbox_repository,
    event_to_outbox_record_translator=your_outbox_record_translator,
    ...
)

# Events are stored in database, published later by worker
transactional_outbox_bus.publish(event)

RabbitMQ

from buz.event.infrastructure.kombu.kombu_event_bus import KombuEventBus

kombu_event_bus = KombuEventBus(
    connection=your_connection,
    publish_strategy=your_publish_strategy,
    publish_retry_policy=you_publish_retry_policy,
    ...
)

# Published and consumed in RabbitMQ
kombu_event_bus.publish(event)

Kafka Integration

from buz.kafka import BuzKafkaEventBus

kafka_bus = KafkaEventBus(
    publish_strategy=your_publish_strategy,
    producer=your_producer,
    logger=your_logger,
    ...
)

# Published and consumed in Kafka
kafka_bus.publish(event)

Kafka Consumer Metrics

Kafka workers (BuzAIOKafkaAsyncConsumer and BuzAIOKafkaMultiThreadedConsumer) emit metrics through a MetricEmitter you pass at construction. Implement that interface in your application (for example with DogStatsD) and query occupancy per minute as sum:messaging.sink_relay.busy_ms over a 1-minute rollup.

Metric Type Tags Description
messaging.sink_relay.log_wait_ms timing subscriber_fqn Time taken to poll a set of records
messaging.sink_relay.poll_delivery_lag_ms timing subscriber_fqn, event_fqn Time from when the record was produced until it was polled
messaging.sink_relay.commit_ms timing subscriber_fqn, event_fqn Time taken to commit a message
messaging.sink_relay.deserialize_ms timing subscriber_fqn, event_fqn Time taken to deserialize a message
messaging.sink_relay.middleware_ms timing subscriber_fqn, event_fqn Time taken to execute the consume middleware chain
messaging.sink_relay.delivery_lag_ms timing subscriber_fqn, event_fqn Time from when the message was produced until the first handler execution
messaging.sink_relay.consume_attempts set subscriber_fqn, event_fqn Retry count for a message
messaging.sink_relay.rejections increment subscriber_fqn, event_fqn Rejections (discard, DLQ, or other on-fail strategy)
messaging.sink_relay.busy_ms increment subscriber_fqn, event_fqn Milliseconds spent executing a subscriber consume for a polled record
messaging.sink_relay.events_processed increment subscriber_fqn, event_fqn Records successfully consumed by a subscriber
messaging.handler.duration_ms timing subscriber_fqn, event_fqn Duration of a successful subscriber handler execution
messaging.handler.unsuccessful_duration_ms timing subscriber_fqn, event_fqn Duration of a failed subscriber handler execution

Async Support

from buz.event.async_event_bus import AsyncEventBus
from buz.query.asynchronous import QueryBus as AsyncQueryBus
from buz.command.asynchronous import CommandHandler as AsyncCommandHandler


# Async event bus
async_event_bus = AsyncEventBus(locator)
await async_event_bus.publish(event)

# Async query bus
async_query_bus = AsyncQueryBus(locator)
await async_query_bus.handle(event)

# Async command bus
async_command_bus = AsyncCommandBus(locator)
await async_command_bus.handle(command)

📦 Message Brokers

Supported Brokers

Broker Sync Async Installation
In-Memory ✅ ✅ Built-in
Kafka ✅ ✅ pip install buz[aiokafka]
RabbitMQ ✅ ❌ pip install buz[kombu]

🧪 Testing

Buz includes testing utilities for unit and integration tests:

from buz.event.sync import SyncEventBus
from buz.locator.sync import InstanceLocator

test_locator = InstanceLocator()
test_bus = SyncEventBus(test_locator)

test_locator.register(EmailSubscriber())
test_bus.publish(UserCreated(user_id="123", email="test@example.com"))

📋 Requirements

  • Python 3.9+
  • Optional dependencies based on features used

🤝 Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Development Setup

# Clone the repository
git clone https://github.com/Feverup/buz.git
cd buz

# Install with development dependencies
make build

# Run tests
make test

# Run linting
make lint

# Format code
make format

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

📚 Documentation

  • Changelog - Release notes and version history

🙋‍♀️ Support

  • Create an Issue for bug reports or feature requests

Made with ❤️ by the Fever Platform Team

Release files for buz 6.0.0

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

Source distribution (sdist)

Source distribution for buz 6.0.0
File Size Uploaded
buz-6.0.0.tar.gz 74.5 kB Details

Built distribution (wheel)

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

Total release size: 249.1 kB

Release files / buz-6.0.0.tar.gz

Download URL buz-6.0.0.tar.gz
Size 74.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9cd185c87e37f0396deeccde32a2f935f3eea2c9566e9d5a42d4b50ef16c405b
BLAKE2b-256 checksum
How to use checksums
fc7b559b7e2f7353d2a174cdcb910e8f33876cf452eac3b66c1a29bf1035d466
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.10.21 Linux/6.17.0-1022-azure

Release files / buz-6.0.0-py3-none-any.whl

Download URL buz-6.0.0-py3-none-any.whl
Size 174.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0d1b1ad094e83330ea6217b22422b64f5598957d4279398006902bab958d1058
BLAKE2b-256 checksum
How to use checksums
db8149d7f495a14df4fde6d5dbfb9198ea1d771214abaa5f057c1be33db55252
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.3 CPython/3.10.21 Linux/6.17.0-1022-azure

Release history Release notifications | RSS feed

This release

6.0.0 This release

2 release files

5.1.0

2 release files

5.0.0

2 release files

4.3.1

2 release files

4.3.0

2 release files

4.2.1

2 release files

4.2.0

2 release files

4.1.0

2 release files

4.0.0

2 release files

3.2.0

2 release files

3.1.1

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.27.1

2 release files

2.27.0

2 release files

2.26.0

2 release files

2.25.0

2 release files

2.24.0

2 release files

2.23.0

2 release files

2.22.1

2 release files

2.22.0

2 release files

2.19.0

2 release files

2.18.0

2 release files

2.17.0

2 release files

2.15.9

2 release files

2.15.6

2 release files

2.15.4

2 release files

2.15.3

2 release files

2.15.0

2 release files

2.14.3

2 release files

2.14.0

2 release files

2.13.1

2 release files

2.11.4

2 release files

2.11.2

2 release files

2.11.1

2 release files

2.11.0

2 release files

2.10.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

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