Order Flow Architecture¶
๐๏ธ System Architecture¶
MongoDB Change Stream โ Order Management Service โ (gRPC) โ Kitchen Batch Tool Service โ SSE โ Frontend
Flow:¶
- MongoDB stores orders in a collection
- Order Management Service watches change stream for new inserts
- Extracts essential data (items, stations, quantities, brand, Otter ID)
- Sends structured data to Kitchen Batch Tool Service via gRPC
- Kitchen Batch Tool Service receives, processes, and streams to frontend via SSE
๐ Monorepo Structure¶
orbital-manager-backend/
โโโ order_management_service/
โ โโโ proto/ โ Owns the Order proto
โ โ โโโ BUILD
โ โ โโโ order_service.proto
โ โ โโโ order_service_pb2.py
โ โ โโโ order_service_pb2_grpc.py
โ โโโ app/
โ โโโ main.py โ Starts MongoDB listener & gRPC client
โ โโโ databases/
โ โโโ utils/
โ โโโ mongo_listener.py โ Watches MongoDB changes
โ
โโโ kitchen_batch_tool_service/
โ โโโ app/
โ โโโ main.py โ Starts gRPC server
โ โโโ routers/
โ โโโ orders_router.py โ SSE endpoint
โ
โโโ shared/
โโโ grpc/ โ Shared gRPC implementations
โ โโโ BUILD
โ โโโ clients/
โ โ โโโ BUILD
โ โ โโโ order_client.py โ Order sending logic
โ โโโ servers/
โ โโโ BUILD
โ โโโ order_server.py โ Order receiving logic
โโโ databases/
โ โโโ mongo_initialization.py โ Async MongoDB connection
โโโ patterns/
โโโ background_service.py โ Base class for listeners
๐ Proto Definition¶
Location: order_management_service/proto/order_service.proto
message OrderItem {
string item_name = 1; // Food item name
string station_name = 2; // Kitchen station
int32 quantity = 3; // Quantity ordered
}
message OrderRequest {
string order_id = 1; // MongoDB _id
string otter_order_id = 2; // Otter Order ID
string brand_name = 3; // Brand (e.g., "Desayuna")
repeated OrderItem order_items = 4; // List of items
string timestamp = 5; // ISO timestamp
string source = 6; // "mongodb_changestream"
}
message OrderResponse {
bool success = 1;
string message = 2;
string order_id = 3;
string processed_at = 4;
}
Data Extraction¶
From MongoDB document, only these fields are extracted:
- _id โ order_id
- OtterOrderId โ otter_order_id
- BrandName โ brand_name
- StationOrders[].OwnStationName โ station_name
- StationOrders[].OrderItems[].Name โ item_name
- StationOrders[].OrderItems[].Quantity โ quantity
๐ง Key Components¶
1. Order Management Service¶
Purpose: Monitors MongoDB and sends orders to kitchen service
Components:
- MongoDB Listener (app/utils/mongo_listener.py)
- Watches change stream with exponential backoff retry (1s โ 60s max)
- Extracts order data when new insert detected
- Calls send_order_to_kitchen()
- Order Client (
shared/grpc/clients/order_client.py) - Parses MongoDB document โ Structured proto messages
- Sends to kitchen service via gRPC
- Returns success/failure status
Startup: 1. Initialize async MongoDB connection 2. Initialize order gRPC client (connects to port 50051) 3. Start MongoDB change stream listener
2. Kitchen Batch Tool Service¶
Purpose: Receives orders and processes batch items
Components:
- Order Server (shared/grpc/servers/order_server.py)
- Receives structured order requests
- Displays to console (grouped by station)
- Publishes to SSE event queue
- Returns response
- SSE Endpoint (
app/routers/orders_router.py) - Streams order events to frontend
- Real-time updates via Server-Sent Events
Startup: 1. Initialize PostgreSQL database 2. Start order gRPC server (listens on port 50051) 3. Serve FastAPI with SSE endpoint
๐ Bazel Dependencies¶
Order Management Service¶
# order_management_service/app/BUILD
deps = [
"//order_management_service/proto:order_service_proto_py", # Own proto
"//shared:shared",
# ...
]
Kitchen Batch Tool Service¶
# kitchen_batch_tool_service/app/BUILD
deps = [
"//order_management_service/proto:order_service_proto_py", # Import proto
"//shared:shared",
# ...
]
Shared gRPC¶
# shared/grpc/clients/BUILD & shared/grpc/servers/BUILD
deps = [
"//order_management_service/proto:order_service_proto_py", # Import proto
"//shared/patterns:patterns",
"//shared/utils:utils",
# ...
]
๐จ Console Output¶
When an order arrives from MongoDB, Kitchen Batch Tool Service displays:
================================================================================
๐ฆ NEW ORDER RECEIVED
================================================================================
Order ID: 67adcfdc15da8840bc9673bd
Otter Order ID: 019c52aa-1232-307c-b56d-1a3af34b458c
Brand: Desayuna
Source: mongodb_changestream
Timestamp: 2025-02-13T10:56:27.756Z
Items (3):
--------------------------------------------------------------------------------
Burger Plancha Station:
โข Grilled Chicken Sandwich (Qty: 2)
โข Classic Burger (Qty: 1)
Salad Station:
โข Caesar Salad (Qty: 1)
================================================================================
๐ SSE Streaming¶
Endpoint: GET /orders/events
Event Data:
{
"order_id": "67adcfdc15da8840bc9673bd",
"otter_order_id": "019c52aa-1232-307c-b56d-1a3af34b458c",
"brand_name": "Desayuna",
"items": [
{
"name": "Grilled Chicken Sandwich",
"station": "Burger Plancha Station",
"quantity": 2
},
{
"name": "Classic Burger",
"station": "Burger Plancha Station",
"quantity": 1
}
],
"timestamp": "2025-02-13T10:56:27.756Z"
}
โ๏ธ Configuration¶
Order Management Service .env¶
# MongoDB Configuration
MONGO_URI=mongodb://localhost:27017
MONGO_DB=your_database
MONGO_ORDERS_COLLECTION=orders
# gRPC Client
GRPC_TARGET=localhost:50051
Kitchen Batch Tool Service .env¶
๐ Running the Services¶
# Terminal 1 - Order Management Service
cd order_management_service
uvicorn app.main:app --reload --port 8000
# Terminal 2 - Kitchen Batch Tool Service
cd kitchen_batch_tool_service
uvicorn app.main:app --reload --port 8001
Health Checks:
curl http://localhost:8000/ping # Order Management
curl http://localhost:8001/ping # Kitchen Batch Tool
SSE Stream:
๐งช Testing¶
Insert a test order into MongoDB:
db.orders.insertOne({
OtterOrderId: "test-order-123",
BrandName: "Test Restaurant",
StationOrders: [
{
OwnStationName: "Grill Station",
OrderItems: [
{ Name: "Burger", Quantity: 2 },
{ Name: "Hot Dog", Quantity: 1 }
]
},
{
OwnStationName: "Fryer Station",
OrderItems: [
{ Name: "French Fries", Quantity: 3 }
]
}
]
})
Expected: 1. Order Management Service logs: "Order sent successfully" 2. Kitchen Batch Tool Service console shows formatted order 3. SSE clients receive real-time event
๐ฎ Adding New RPC Services¶
When adding new RPC services (e.g., Inventory, Payment):
1. Create Proto in Sender Service¶
inventory_service/
โโโ proto/
โโโ BUILD
โโโ inventory_service.proto
โโโ inventory_service_pb2.py
โโโ inventory_service_pb2_grpc.py
2. Create Client & Server in Shared¶
shared/grpc/
โโโ clients/
โ โโโ inventory_client.py โ New client
โโโ servers/
โโโ inventory_server.py โ New server
3. Update BUILD Files¶
4. Name Pattern¶
- Handler:
InventoryHandler - Server:
InventoryServer - Client:
InventoryClient - Functions:
start_inventory_server(),initialize_inventory_client()
โ Benefits¶
- Clear Ownership: Proto lives with the service that defines it
- Bazel Dependencies: Explicit dependency tree via BUILD files
- Scalable: Easy to add new RPC services
- Type Safety: Structured proto messages with proper types
- Performance: Small payloads (only essential data)
- Maintainable: Clear naming, organized structure
- Real-time: SSE streaming for frontend updates
- Async MongoDB: Non-blocking with retry logic
๐ฏ Summary¶
โ
Proto Location: Owned by sender (order_management_service/proto/)
โ
Shared gRPC: Reusable clients/servers in shared/grpc/
โ
Clean Naming: OrderHandler, OrderClient, OrderServer
โ
Bazel Dependencies: Proper dependency declarations
โ
Structured Data: Only essential fields transmitted
โ
SSE Integration: Real-time streaming to frontend
โ
Async MongoDB: Non-blocking with retry logic