Skip to content

Cookbook: High-Scale Microservices ​

In traditional systems, microservices are a source of endless "plumbing" anxiety. You have to configure service meshes, manage mTLS certificates, write client-side retries, and handle distributed transaction failures. If the Inventory service goes down, the Order service crashes in a way that is incredibly hard to debug.

Carotene abstracts the infrastructure layer entirely. When you define an internal communication boundary, the compiler automatically generates the secure gRPC or mTLS-encrypted transport layer. You don't connect services; you declare architectural dependencies.

1. The Architectural Blueprint ​

In this scenario, we are building a distributed E-commerce system. We have a public-facing OrderService that must reach out to a strictly private, internal InventoryService to reserve stock.

By defining both services in the same monorepo, Carotene understands the internal topology and handles the networking automatically.

dart
// apps/order-service/orders.carrot
backend OrderService {
  // We define an internal integration
  integration InventoryService {
    ReserveStock(itemId: store.Stock.id, qty: store.Stock.count) -> Boolean
  }

  function Checkout(orderId: store.Order.id) {
    reads store.Order
    calls integration.InventoryService // <-- This is the cross-service boundary
    
    order = store.Order(orderId)
    
    // The Generative Operator handles the distributed transaction logic
    // (e.g., Saga pattern or 2-phase commit)
    @("Call InventoryService to reserve stock. If it fails, roll back the order status.")
    
    return true
  }
}

2. The Internal Service (Encapsulation) ​

The InventoryService remains completely hidden from the internet. It does not expose a public API; it only responds to internal calls from authorized services within your infrastructure.

dart
// apps/inventory-service/stock.carrot
backend InventoryService {
  function ReserveStock(itemId: store.Stock.id, qty: store.Stock.count) {
    updates store.Stock
    
    stock = store.Stock(itemId)
    if (stock.count < qty) {
      rejects with "Out of stock"
    }
    
    stock.count = stock.count - qty
    return true
  }
}

3. The Proof (Testing Distributed Systems) ​

Testing microservices is historically difficult because you usually have to "docker-compose up" the entire universe.

In Carotene, you don't do that. You use the mock primitive to intercept the internal calls boundary. You test the OrderService as if the InventoryService exists, without ever needing to actually spin it up.

dart
// apps/order-service/tests/Checkout.test.carrot
test "OrderService handles Inventory failure gracefully" {
  given mock store.Order { id: "order_1" }
  
  // 1. Mock the internal service boundary to return a failure
  mock integration.InventoryService.ReserveStock -> false
  
  // 2. Execute the function
  result = Checkout("order_1")
  
  // 3. Assert the order was correctly handled (e.g., status is 'Failed')
  asserts store.Order("order_1").status == "Failed"
}

4. Compile and Deploy ​

When you run carrot build:

  1. Infrastructure Generation: Carotene generates the Kubernetes ingress rules, the internal mTLS certificates, and the gRPC client/server stubs for InventoryService.
  2. Type Safety: If the InventoryService signature changes (e.g., you rename itemId to productId), the OrderService will fail to compile immediately. The contract is strictly enforced across the monorepo.
  3. Sandbox Validation: The compiler verifies that the OrderService has the calls integration.InventoryServicepermission. If it doesn't, the build fails.
  4. Resiliency: The AI logic synthesized for the @(...) operator automatically includes retry logic and rollback stubs, ensuring that your distributed system doesn't leave data in an inconsistent state if a request times out.