Skip to content

Order Flow Architecture

๐Ÿ—๏ธ System Architecture

MongoDB Change Stream โ†’ Order Management Service โ†’ (gRPC) โ†’ Kitchen Batch Tool Service โ†’ SSE โ†’ Frontend

Flow:

  1. MongoDB stores orders in a collection
  2. Order Management Service watches change stream for new inserts
  3. Extracts essential data (items, stations, quantities, brand, Otter ID)
  4. Sends structured data to Kitchen Batch Tool Service via gRPC
  5. 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

# gRPC Server
GRPC_PORT=50051

๐Ÿš€ 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:

curl -N http://localhost:8001/orders/events


๐Ÿงช 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

# Receiver service BUILD
deps = [
    "//inventory_service/proto:inventory_service_proto_py",
    # ...
]

4. Name Pattern

  • Handler: InventoryHandler
  • Server: InventoryServer
  • Client: InventoryClient
  • Functions: start_inventory_server(), initialize_inventory_client()

โœ… Benefits

  1. Clear Ownership: Proto lives with the service that defines it
  2. Bazel Dependencies: Explicit dependency tree via BUILD files
  3. Scalable: Easy to add new RPC services
  4. Type Safety: Structured proto messages with proper types
  5. Performance: Small payloads (only essential data)
  6. Maintainable: Clear naming, organized structure
  7. Real-time: SSE streaming for frontend updates
  8. 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