New alert service
This commit is contained in:
191
shared/messaging/README.md
Normal file
191
shared/messaging/README.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Unified Messaging Architecture
|
||||
|
||||
This document describes the standardized messaging system used across all bakery-ia microservices.
|
||||
|
||||
## Overview
|
||||
|
||||
The unified messaging architecture provides a consistent approach for:
|
||||
- Publishing business events (inventory changes, user actions, etc.)
|
||||
- Publishing user-facing alerts, notifications, and recommendations
|
||||
- Consuming events from other services
|
||||
- Maintaining service-to-service communication patterns
|
||||
|
||||
## Core Components
|
||||
|
||||
### 1. UnifiedEventPublisher
|
||||
The main publisher for all event types, located in `shared/messaging/messaging_client.py`:
|
||||
|
||||
```python
|
||||
from shared.messaging import UnifiedEventPublisher, EVENT_TYPES, RabbitMQClient
|
||||
|
||||
# Initialize
|
||||
rabbitmq_client = RabbitMQClient(settings.RABBITMQ_URL, service_name="my-service")
|
||||
await rabbitmq_client.connect()
|
||||
event_publisher = UnifiedEventPublisher(rabbitmq_client, "my-service")
|
||||
|
||||
# Publish business events
|
||||
await event_publisher.publish_business_event(
|
||||
event_type=EVENT_TYPES.INVENTORY.STOCK_ADDED,
|
||||
tenant_id=tenant_id,
|
||||
data={"ingredient_id": "123", "quantity": 100.0}
|
||||
)
|
||||
|
||||
# Publish alerts (action required)
|
||||
await event_publisher.publish_alert(
|
||||
event_type="procurement.po_approval_needed",
|
||||
tenant_id=tenant_id,
|
||||
severity="high", # urgent, high, medium, low
|
||||
data={"po_id": "456", "supplier_name": "ABC Corp"}
|
||||
)
|
||||
|
||||
# Publish notifications (informational)
|
||||
await event_publisher.publish_notification(
|
||||
event_type="production.batch_completed",
|
||||
tenant_id=tenant_id,
|
||||
data={"batch_id": "789", "product_name": "Bread"}
|
||||
)
|
||||
|
||||
# Publish recommendations (suggestions)
|
||||
await event_publisher.publish_recommendation(
|
||||
event_type="forecasting.demand_surge_predicted",
|
||||
tenant_id=tenant_id,
|
||||
data={"product_name": "Croissants", "surge_percentage": 25.0}
|
||||
)
|
||||
```
|
||||
|
||||
### 2. Event Types Constants
|
||||
Use predefined event types for consistency:
|
||||
|
||||
```python
|
||||
from shared.messaging import EVENT_TYPES
|
||||
|
||||
# Inventory events
|
||||
EVENT_TYPES.INVENTORY.INGREDIENT_CREATED
|
||||
EVENT_TYPES.INVENTORY.STOCK_ADDED
|
||||
EVENT_TYPES.INVENTORY.LOW_STOCK_ALERT
|
||||
|
||||
# Production events
|
||||
EVENT_TYPES.PRODUCTION.BATCH_CREATED
|
||||
EVENT_TYPES.PRODUCTION.BATCH_COMPLETED
|
||||
|
||||
# Procurement events
|
||||
EVENT_TYPES.PROCUREMENT.PO_APPROVED
|
||||
EVENT_TYPES.PROCUREMENT.DELIVERY_SCHEDULED
|
||||
```
|
||||
|
||||
### 3. Service Integration Pattern
|
||||
|
||||
#### In Service Main.py:
|
||||
```python
|
||||
from shared.messaging import UnifiedEventPublisher, ServiceMessagingManager
|
||||
|
||||
class MyService(StandardFastAPIService):
|
||||
def __init__(self):
|
||||
self.messaging_manager = None
|
||||
self.event_publisher = None # For alerts/notifications
|
||||
self.unified_publisher = None # For business events
|
||||
|
||||
super().__init__(
|
||||
service_name="my-service",
|
||||
# ... other params
|
||||
enable_messaging=True
|
||||
)
|
||||
|
||||
async def _setup_messaging(self):
|
||||
try:
|
||||
self.messaging_manager = ServiceMessagingManager("my-service", settings.RABBITMQ_URL)
|
||||
success = await self.messaging_manager.setup()
|
||||
if success:
|
||||
self.event_publisher = self.messaging_manager.publisher
|
||||
self.unified_publisher = self.messaging_manager.publisher
|
||||
|
||||
self.logger.info("Messaging setup completed")
|
||||
else:
|
||||
raise Exception("Failed to setup messaging")
|
||||
except Exception as e:
|
||||
self.logger.error("Messaging setup failed", error=str(e))
|
||||
raise
|
||||
|
||||
async def on_startup(self, app: FastAPI):
|
||||
await super().on_startup(app)
|
||||
|
||||
# Pass publishers to services
|
||||
my_service = MyAlertService(self.event_publisher)
|
||||
my_event_service = MyEventService(self.unified_publisher)
|
||||
|
||||
# Store in app state if needed
|
||||
app.state.my_service = my_service
|
||||
app.state.my_event_service = my_event_service
|
||||
|
||||
async def on_shutdown(self, app: FastAPI):
|
||||
if self.messaging_manager:
|
||||
await self.messaging_manager.cleanup()
|
||||
await super().on_shutdown(app)
|
||||
```
|
||||
|
||||
#### In Service Implementation:
|
||||
```python
|
||||
from shared.messaging import UnifiedEventPublisher
|
||||
|
||||
class MyEventService:
|
||||
def __init__(self, event_publisher: UnifiedEventPublisher):
|
||||
self.publisher = event_publisher
|
||||
|
||||
async def handle_business_logic(self, tenant_id: UUID, data: Dict[str, Any]):
|
||||
# Publish business events
|
||||
await self.publisher.publish_business_event(
|
||||
event_type="mydomain.action_performed",
|
||||
tenant_id=tenant_id,
|
||||
data=data
|
||||
)
|
||||
```
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Old Pattern (Deprecated):
|
||||
```python
|
||||
# OLD - Don't use this anymore
|
||||
from shared.alerts.base_service import BaseAlertService
|
||||
|
||||
class MyService(BaseAlertService):
|
||||
def __init__(self, config):
|
||||
super().__init__(config)
|
||||
|
||||
async def send_alert(self, tenant_id, data):
|
||||
await self.publish_item(tenant_id, data, item_type="alert")
|
||||
```
|
||||
|
||||
### New Pattern (Recommended):
|
||||
```python
|
||||
# NEW - Use UnifiedEventPublisher for all event types
|
||||
from shared.messaging import UnifiedEventPublisher
|
||||
|
||||
class MyService:
|
||||
def __init__(self, event_publisher: UnifiedEventPublisher):
|
||||
self.publisher = event_publisher
|
||||
|
||||
async def send_alert(self, tenant_id: UUID, data: Dict[str, Any]):
|
||||
await self.publisher.publish_alert(
|
||||
event_type="mydomain.alert_type",
|
||||
tenant_id=tenant_id,
|
||||
severity="high",
|
||||
data=data
|
||||
)
|
||||
```
|
||||
|
||||
## Event Routing
|
||||
|
||||
Events are routed using the following patterns:
|
||||
- **Alerts**: `alert.{domain}.{severity}` (e.g., `alert.inventory.high`)
|
||||
- **Notifications**: `notification.{domain}.info` (e.g., `notification.production.info`)
|
||||
- **Recommendations**: `recommendation.{domain}.medium` (e.g., `recommendation.forecasting.medium`)
|
||||
- **Business Events**: `business.{event_type}` (e.g., `business.inventory_stock_added`)
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Consistent Naming**: Use lowercase, dot-separated event types (e.g., `inventory.stock.added`)
|
||||
2. **Tenant Awareness**: Always include tenant_id for multi-tenant operations
|
||||
3. **Data Minimization**: Include only essential data in events
|
||||
4. **Error Handling**: Always wrap event publishing in try-catch blocks
|
||||
5. **Service Names**: Use consistent service names matching your service definition
|
||||
6. **Lifecycle Management**: Always clean up messaging resources during service shutdown
|
||||
Reference in New Issue
Block a user