# ContextMessageBus

A Python library that adds multi-tenant context routing on top of the [MessageBus](https://pip.e-deploy.com.br) framework. Messages and events carry a `"context"` header that determines which tenant/context they belong to.

## Installation

```bash
poetry install
```

## Usage

### ContextMessageBus

Wraps a `MessageBus` and automatically stamps all outgoing messages/events with a fixed context name:

```python
from contextmessagebus import ContextMessageBus

context_bus = ContextMessageBus(context="tenant_a", message_bus=base_bus)
context_bus.send_message(component, message)  # "context" header set automatically
```

### MultiContextMessageBus

Thread-local context variant for multi-threaded environments:

```python
from contextmessagebus import MultiContextMessageBus

multi_bus = MultiContextMessageBus(message_bus=base_bus)
multi_bus.set_current_context("tenant_a")
multi_bus.send_message(component, message)  # uses thread-local context
```

### ContextMessageHandlerBuilder

Abstract builder that creates per-context message handlers. Subclass it to define how contexts are built and how handlers are created per context:

```python
from contextmessagehandler import ContextMessageHandlerBuilder

class MyBuilder(ContextMessageHandlerBuilder[MyConfig]):
    def build_context(self):
        return {"tenant_a": MyConfig(...), "tenant_b": MyConfig(...)}

    def build_singletons_with_context(self, context_dict):
        ...

    def build_message_handler_with_context(self, context):
        return MyHandler(context)

    def destroy_message_handler_with_context(self, context, message_handler):
        ...

    def destroy_singletons_with_context(self, context_dict):
        ...
```

### AutoupdateContextMessageHandlerBuilder

Extends `ContextMessageHandlerBuilder` with a background thread that periodically refreshes the context list on a TTL interval, hot-adding and removing contexts at runtime.

### DynamicContextMessageHandlerBuilder

Creates contexts lazily on first request using thread-safe double-checked locking, rather than pre-building all contexts at startup. If `build_context()` returns `None`, the result is not cached, allowing retries on subsequent requests.

### Thread safety

`Context.request_data` is thread-local — each thread sees its own value even when sharing the same `Context` instance across concurrent requests.

## Scripts

Setup Claude Code skills (symlinks `.claude/skills/*` into `~/.claude/skills/`):

```bash
poetry run task setup-skills
```

## Testing

```bash
poetry run pytest
```

## Requirements

- Python >= 3.8
- MessageBus >= 1.2, < 2