Skip to content

mjunaidca/ai-pizza-challenge-dapr-workflows

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI Pizza Shop - Dapr Workflow DACA Challenge

Here's the minimal solution for the AI Pizza Shop Dapr Workflow Challenge.

Workflow Visualization

The following diagram illustrates the high-level flow of the OrderProcessingWorkflow and its child KitchenPreparationWorkflow:

graph TD
    %% Main API entry point
    Start[API: POST /order_pizza] --> OrderFlow
    
    %% Main Order Processing Workflow
    subgraph OrderFlow[Order Processing Workflow]
        direction TB
        O_Start([Start]) --> ValidateOrder[1. Validate Order]
        ValidateOrder --> SuggestToppings[2. AI Topping Suggestions]
        SuggestToppings --> ProcessPayment[3. Process Payment<br>retries: 3 times, 1s delay]
        ProcessPayment --> CallKitchen[4. Start Kitchen Workflow]
        CallKitchen --> NotifyCustomer[5. Send Confirmation<br>to Customer]
        NotifyCustomer --> O_End([Order Complete])
        
        %% Error paths
        ValidateOrder -.-> OrderValidationError[❌ Invalid Order<br>Return 400]
        ProcessPayment -.-> PaymentError[❌ Payment Failed<br>Return 402]
    end
    
    %% Kitchen Workflow - connected to the main flow
    CallKitchen --> KitchenFlow
    
    %% Kitchen Preparation Workflow
    subgraph KitchenFlow[Kitchen Preparation Workflow]
        direction TB
        K_Start([Start]) --> ForEachPizza{{For each pizza<br>in order}}
        ForEachPizza --> MakeDough[1. Prepare Dough]
        MakeDough --> AddToppings[2. Add Toppings]
        AddToppings --> StartBaking["3. Start Baking<br>(Log: START_BAKING)"]
        StartBaking --> BakeTimer["4. Wait for Baking<br>(Timer: ~12 mins)"]
        BakeTimer --> FinishBaking["5. Finish Baking<br>(Log: FINISH_BAKING)"]
        FinishBaking --> NextPizza{More pizzas?}
        NextPizza -- Yes --> ForEachPizza
        NextPizza -- No --> K_End([All Pizzas Ready])
    end
    
    %% Styling
    classDef process fill:#d4f1f9,stroke:#05386b,stroke-width:1px
    classDef special fill:#f9d4f1,stroke:#4b0082,stroke-width:2px
    classDef timer fill:#d4f9d4,stroke:#228b22,stroke-width:1px
    classDef error fill:#f9d4d4,stroke:#8b0000,stroke-width:1px
    classDef loop fill:#f9f9d4,stroke:#8b8b00,stroke-width:1px
    
    %% Apply styles
    class ValidateOrder,SuggestToppings,NotifyCustomer,MakeDough,AddToppings,StartBaking,FinishBaking process
    class ProcessPayment special
    class BakeTimer timer
    class OrderValidationError,PaymentError error
    class ForEachPizza,NextPizza loop
Loading

Setup

Get K8 Cluster and Tilt Setup locally. Ensure you are using containerd runtime - if it's docker then open Tiltfile and comment the nerdctl command at start. It by default uses docker. Now clone and Run the Code

tilt up

Now in Browser Open:

Jaegor can be optionally setup - for it just enable it at end of Tilt File. The config is already there and interface will be at http://localhost:16686/

You can test these either through UI at /docs or cli i.e curl.

Step 1: Start the Pizza Order Workflow

  • Action: Send a POST request to the /order_pizza endpoint.

  • Method: POST

  • URL: http://localhost:30080/order_pizza

  • Body (JSON):

    {
      "customer_name": "Ada Lovelace",
      "pizza_type": "Margherita",
      "quantity": 1
    }

    You can also try quantity: 2 to see the kitchen workflow process multiple items.

  • Example using curl:

    curl -X POST -H "Content-Type: application/json" \
    -d '{"customer_name": "Ada Lovelace", "pizza_type": "Margherita", "quantity": 1}' \
    http://localhost:30080/order_pizza
  • Expected Response: You should receive a JSON response indicating the workflow was scheduled successfully, including an instance_id. Note this instance_id (it will look something like pizza-order-xxxxxxxxxxxx).

    {
      "message": "Pizza order workflow scheduled successfully.",
      "instance_id": "pizza-order-abcdef123456"
    }

Step 2: Observe Application Logs

  • Action: Monitor the console where you ran the dapr run ... python main.py command.
  • What to look for:
    • Order WF '<instance_id>': Starting for Ada Lovelace, 1 x Margherita.
    • Logs from ValidateOrderActivity.
    • Logs from AIToppingSuggestionActivity.
    • Activity (WF '<instance_id>'): Payment attempt 1 failed (simulated). (and attempt 2)
    • Activity (WF '<instance_id>'): Payment attempt 3 successful...
    • Kitchen WF '<child_instance_id>': Starting preparation...
    • Logs for MakeDoughActivity, AddToppingsActivity.
    • Kitchen WF '<child_instance_id>': Baking Margherita (item 1) for 10s...
    • Logs from BakePizzaActivity (START_BAKING and FINISH_BAKING).
    • Kitchen WF '<child_instance_id>': All 1 Margherita(s) prepared successfully.
    • Logs from NotifyCustomerActivity.
    • Order WF '<instance_id>': Order for Ada Lovelace (1x Margherita w/ Fresh Basil) processed successfully.
    • The workflow setting custom statuses at various stages.

Step 3: Check Workflow Status

You can check the workflow status using the application's endpoint or the Dapr API directly. Replace <YOUR_INSTANCE_ID> with the actual ID from Step 1.

  • Method: GET

    • URL: http://localhost:30080/workflows/<YOUR_INSTANCE_ID>/status
    • Example curl:
      curl http://localhost:30080/workflows/pizza-order-abcdef123456/status
  • What to look for:

    • Initially, runtimeStatus might be RUNNING.
    • Eventually, it should become COMPLETED if everything succeeds.
    • If an unhandled error occurs (e.g., if validation fails and you send an invalid order), it might be FAILED.
    • You will also see the customStatus messages set by the workflow.

Step 4: Observe Payment Retries in Logs

  • As noted in Step 2, the logs for ProcessPaymentActivity will show the first two attempts failing due to the simulation in main.py.
  • You'll see the Dapr Workflow engine automatically retrying the activity based on the defined RetryPolicy.
  • The third attempt will succeed.

Step 5: Observe Child Workflow and Timer in Logs

  • Look for log entries indicating the start and completion of the KitchenPreparationWorkflow (the child workflow). It will have its own instance ID, typically related to the parent's ID.
  • Inside the kitchen workflow logs:
    • Observe MakeDoughActivity and AddToppingsActivity logs.
    • Pay attention to the "Baking ... for 10s..." message. The workflow will pause here due to ctx.create_timer().
    • After 10 seconds, you'll see the "Finished baking" log.
    • If quantity was greater than 1, you'll see this dough-toppings-bake sequence repeat.

Step 6: (Optional) Test Invalid Order

Try starting a workflow with invalid data to see the validation fail:

  • Body (JSON):
    {
      "customer_name": "Test User",
      "pizza_type": "",
      "quantity": 0
    }
  • Observe:
    • The OrderProcessingWorkflow should start.
    • ValidateOrderActivity will raise an error.
    • The workflow should transition to a FAILED state. Check the logs and status endpoint.

Step 7: (Optional) Using Other Management Endpoints

The application includes generic endpoints for managing workflows. You can use these with your instance_id:

  • Pause: POST /workflows/<YOUR_INSTANCE_ID>/pause
  • Resume: POST /workflows/<YOUR_INSTANCE_ID>/resume
  • Terminate: POST /workflows/<YOUR_INSTANCE_ID>/terminate
  • Purge: POST /workflows/<YOUR_INSTANCE_ID>/purge (after completion/failure)

While the pizza workflow runs relatively quickly, you could try pausing it during the 10-second baking timer in the KitchenPreparationWorkflow to see the effect.

About

AI Pizza Shop - Dapr Workflow DACA Challenge

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published