Vercel Logo

Add the kitchen step

One step makes a workflow. Two steps makes the value obvious.

Right now processOrder calls sendOrderConfirmation and returns. The kitchen has no idea there's an order. The customer thinks Sal is making their pizza, but Sal is, in fact, taking a nap.

Time to add acknowledgeKitchen. It updates the order status to "in-the-kitchen" so the ops dashboard knows. In a real shop this is where you'd ping a kitchen printer or your POS. We're keeping it boring on purpose. The point isn't what the step does. The point is that adding another step to a workflow takes two lines.

Outcome

Add acknowledgeKitchen as a second step in processOrder. After placing an order, the run timeline shows two steps and the kitchen ops page shows the order waiting in the oven.

Fast Track

  1. Create workflows/steps/acknowledge-kitchen.ts with the "use step" directive. Update the store status to "in-the-kitchen".
  2. Import the step in workflows/process-order.ts. await it after sendOrderConfirmation.
  3. Place an order. Open /kitchen and see it sitting in the oven.

Hands-on exercise

1. Write the step.

Create workflows/steps/acknowledge-kitchen.ts:

workflows/steps/acknowledge-kitchen.ts
import { updateStatus } from "@/lib/orders-store";
import type { Order } from "@/lib/pizza";
 
export async function acknowledgeKitchen(order: Order): Promise<void> {
  "use step";
 
  await new Promise((resolve) => setTimeout(resolve, 200));
 
  updateStatus(order.id, "in-the-kitchen");
}

Same shape as sendOrderConfirmation. Async function, "use step" first, do the work, persist any side effect through the store. The 200ms setTimeout is fake latency so the dashboard timeline has something to show. Real code wouldn't have it.

Why no try/catch?

We didn't wrap the body in error handling. If the store update throws, the step throws, and the runtime retries. That's the whole deal. You only catch errors when you have a specific recovery plan, which here you don't.

2. Call it from the workflow.

Add the import and a second await in workflows/process-order.ts:

workflows/process-order.ts
import type { Order } from "@/lib/pizza";
import { sendOrderConfirmation } from "./steps/send-order-confirmation";
import { acknowledgeKitchen } from "./steps/acknowledge-kitchen";
 
export async function processOrder(order: Order): Promise<{ orderId: string }> {
  "use workflow";
 
  await sendOrderConfirmation(order);
  await acknowledgeKitchen(order);
 
  return { orderId: order.id };
}

Two lines: an import and an await. That's the entire change.

Try It

Place an order from http://localhost:3000. Then open http://localhost:3000/kitchen in a new tab.

The kitchen page should show your order sitting in the oven:

1 pizza in the oven.

large Sal's Special           [Mark ready]
Marge Pepperoni · thin crust

The "Mark ready" button doesn't work yet. Clicking it 404s because we haven't built /api/kitchen/ready. That's section 3. For now, the order sits there forever, which is exactly what the kitchen would tell you if you called.

In the dashboard at http://localhost:3700, the run timeline now shows two steps:

processOrder                completed   612ms
  ├─ sendOrderConfirmation    completed   389ms
  └─ acknowledgeKitchen       completed   208ms

The order doesn't progress past "in-the-kitchen" because the workflow returns right after that step. We'll keep extending it.

Commit

feat(workflow): add acknowledgeKitchen step

Done-When

  • workflows/steps/acknowledge-kitchen.ts exists with the "use step" directive
  • processOrder awaits acknowledgeKitchen after sendOrderConfirmation
  • Placing an order results in the kitchen page showing the order in the oven
  • The dashboard timeline shows two completed steps for the run

Solution

workflows/steps/acknowledge-kitchen.ts:

workflows/steps/acknowledge-kitchen.ts
import { updateStatus } from "@/lib/orders-store";
import type { Order } from "@/lib/pizza";
 
export async function acknowledgeKitchen(order: Order): Promise<void> {
  "use step";
 
  await new Promise((resolve) => setTimeout(resolve, 200));
 
  updateStatus(order.id, "in-the-kitchen");
}

workflows/process-order.ts:

workflows/process-order.ts
import type { Order } from "@/lib/pizza";
import { sendOrderConfirmation } from "./steps/send-order-confirmation";
import { acknowledgeKitchen } from "./steps/acknowledge-kitchen";
 
export async function processOrder(order: Order): Promise<{ orderId: string }> {
  "use workflow";
 
  await sendOrderConfirmation(order);
  await acknowledgeKitchen(order);
 
  return { orderId: order.id };
}

Same skeleton, more steps. We'll repeat this pattern for the rest of the course.

Was this helpful?

supported.