Metadata-Version: 2.4
Name: protobus
Version: 1.3.1
Summary: The Protobus micro-services framework - Python port
Author-email: Ariel Laub <ariel@laub.co.il>
License: MIT
Project-URL: Homepage, https://github.com/ArielLaub/protobus-py
Project-URL: Repository, https://github.com/ArielLaub/protobus-py
Project-URL: Issues, https://github.com/ArielLaub/protobus-py/issues
Keywords: micro services,bus,amqp,rabbitmq,protobuf,scalable
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Distributed Computing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: aio-pika>=9.0.0
Requires-Dist: protobuf>=4.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"

# Protobus Python

A lightweight, scalable microservices message bus for Python. Leverages RabbitMQ for message routing and load balancing, combined with Protocol Buffers for efficient, type-safe serialization.

> **Note:** This is the official Python port of [Protobus](https://github.com/ArielLaub/protobus), originally written in TypeScript. The API and architecture are designed to be as close to the original as possible.

## Why Protobus?

Unlike transport-agnostic frameworks that abstract away the message broker, Protobus **embraces RabbitMQ's native capabilities** directly. We leverage topic exchanges, routing keys, competing consumers, dead-letter queues, and message persistence - rather than re-implementing routing logic at the application level.

### RabbitMQ-Native Approach

**Message Routing**: By delegating routing to RabbitMQ's Erlang runtime instead of your Python process, Protobus eliminates the double-processing that transport-agnostic frameworks impose. The broker handles competing consumers, topic-based routing, and dead-letter queues natively.

**Binary Serialization**: Protocol Buffers provide 3-10x smaller payloads than JSON, with compile-time type safety and built-in backward compatibility. No more runtime schema guessing or JSON parsing overhead.

### Polyglot Advantage

Since Protobus uses standard Protobuf schemas and AMQP protocol, implementing clients in other languages is straightforward. Currently available in **TypeScript/Node.js** and **Python**, with Java, Go, or Rust implementations requiring minimal effort.

## Features

- **RPC Communication**: Request-response pattern over message queues
- **Event System**: Publish-subscribe with topic-based routing and wildcards
- **Auto-Reconnection**: Exponential backoff with jitter for resilient connections
- **Message Retry**: Automatic retry with dead-letter queue (DLQ) support
- **Custom Types**: Extensible type system (BigInt, Timestamp built-in)
- **Async/Await**: Built on asyncio and aio-pika for modern Python
- **CLI Tools**: Generate types and service stubs from .proto files
- **Lifecycle Management**: RunnableService with graceful shutdown handling

## Requirements

- Python 3.10 or higher
- RabbitMQ 3.8 or higher

## Installation

```bash
pip install protobus
```

Or install from source:

```bash
git clone https://github.com/ArielLaub/protobus-py.git
cd protobus-py
pip install -e .
```

## Quick Start

### 1. Start RabbitMQ

```bash
docker-compose up -d
```

### 2. Create a Service

```python
from protobus import RunnableService, Context

class CalculatorService(RunnableService):
    @property
    def service_name(self) -> str:
        return "calculator.MathService"

    async def add(self, data: dict, actor: str, correlation_id: str) -> dict:
        return {"result": data["a"] + data["b"]}

    async def multiply(self, data: dict, actor: str, correlation_id: str) -> dict:
        return {"result": data["a"] * data["b"]}
```

### 3. Run the Service

```python
import asyncio
from protobus import Context

async def main():
    ctx = Context()
    await ctx.init("amqp://guest:guest@localhost:5672/")

    # Start with lifecycle management (handles SIGINT/SIGTERM)
    await CalculatorService.start(ctx, CalculatorService)

asyncio.run(main())
```

### 4. Create a Client

```python
import asyncio
from protobus import Context, ServiceProxy

async def main():
    ctx = Context()
    await ctx.init("amqp://guest:guest@localhost:5672/")

    # Create proxy for the calculator service
    calc = ServiceProxy(ctx, "calculator.MathService")
    await calc.init()

    # Make RPC calls
    result = await calc.add({"a": 5, "b": 3})
    print(f"5 + 3 = {result['result']}")  # Output: 5 + 3 = 8

    result = await calc.multiply({"a": 4, "b": 7})
    print(f"4 * 7 = {result['result']}")  # Output: 4 * 7 = 28

    await ctx.close()

asyncio.run(main())
```

## CLI Tools

Protobus includes CLI tools for code generation:

```bash
# Generate Python types from .proto files
protobus generate

# Generate a service stub
protobus generate:service calculator.MathService

# Show project setup instructions
protobus init
```

Configure in `pyproject.toml`:

```toml
[tool.protobus]
protoDir = "./proto"
typesOutput = "./types/proto.py"
servicesDir = "./services"
```

## Documentation

- [Getting Started](docs/getting-started.md) - Installation and first service
- [Architecture](docs/architecture.md) - System design and components
- [Configuration](docs/configuration.md) - Environment variables and options
- [Message Flow](docs/message-flow.md) - How messages move through the system
- [CLI Tools](docs/cli.md) - Code generation commands
- [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions

### API Reference

- [Context](docs/api/context.md) - Connection management
- [MessageService](docs/api/message-service.md) - Building services
- [RunnableService](docs/api/runnable-service.md) - Services with lifecycle management
- [ServiceProxy](docs/api/service-proxy.md) - Calling services
- [ServiceCluster](docs/api/service-cluster.md) - Managing multiple services
- [Events](docs/api/events.md) - Publish-subscribe patterns

### Advanced Topics

- [Error Handling](docs/advanced/error-handling.md) - Retries and DLQ
- [Custom Logger](docs/advanced/custom-logger.md) - Logging integration
- [Custom Types](docs/advanced/custom-types.md) - Extending the type system

## Sample Application

The `sample/combatGame` directory contains a complete example - a turn-based battle royale game with 6 AI players demonstrating:

- Multiple services communicating via RPC
- Event-based game state synchronization
- Different player strategies

Run it:

```bash
python sample/combatGame/game_runner.py
```

## Cross-Language Compatibility

This library is fully wire-compatible with the original [TypeScript Protobus](https://github.com/ArielLaub/protobus). Services written in Python and TypeScript can communicate seamlessly on the same message bus, thanks to Protocol Buffers' language-agnostic serialization format.

## Original Project

This is the Python port of [Protobus](https://github.com/ArielLaub/protobus) (TypeScript). The original project provides identical functionality for Node.js/TypeScript environments.

## License

MIT License - Copyright (c) Remarkable Games Ltd.

See [LICENSE](LICENSE) for details.
