Order Processing Workflow
This example shows how to build an e-commerce order processing workflow, including validation, parallel payment and inventory checks, shipping, and confirmation.
-
Define Workflow with Retry Policy
Start by defining the workflow and a default retry policy for its steps.
import * as v from '@identity-flow/sdk/valibot';import { NonRetryableError, defineWorkflow } from '@identity-flow/sdk';// Assuming Valibot for schema// Define an input schema for the orderconst OrderInputSchema = v.object({orderId: v.string(),customerId: v.string(),items: v.array(v.object({ productId: v.string(), quantity: v.number() })),totalAmount: v.number(),shippingAddress: v.object({ street: v.string(), city: v.string(), zip: v.string() }),});export default defineWorkflow('order-processing-example',{schema: OrderInputSchema,retries: { limit: 3, delay: '30 seconds', backoff: 'exponential' },},async (flow) => {// Workflow steps will go here},); -
Validate Order Details
Perform initial validation on the order.
flow.paramsis already validated by the workflow schema, but you might have custom business rule checks.// Inside the async (flow) => { ... }const validatedOrder = await flow.do('validate order business rules', async () => {if (!flow.params.items?.length) {// Throw a NonRetryableError if it's a business rule violation that shouldn't be retried.throw new NonRetryableError('Order must contain items');}// Perform other business rule validations if necessary...console.log('Order business rules validated for:', flow.params.orderId);return flow.params; // Return the validated (or transformed) order data}); -
Process Payment & Check Inventory (Parallel)
Use
Promise.allto execute payment processing and inventory checking concurrently for efficiency.// Inside the async (flow) => { ... }const [paymentResult, inventoryStatus] = await Promise.all([flow.do('process payment', async () => {console.log('Processing payment for order:', validatedOrder.orderId);// Replace with actual payment gateway integrationreturn processPayment(validatedOrder.customerId, validatedOrder.totalAmount);}),flow.do('check inventory', async () => {console.log('Checking inventory for order:', validatedOrder.orderId);// Replace with actual inventory check logicreturn checkInventoryAvailability(validatedOrder.items);}),]);// Handle payment failureif (!paymentResult.success) {flow.error('Payment failed for order:', validatedOrder.orderId, paymentResult.failureReason);// Optionally, trigger a compensation logic, like voiding an authorizationthrow new NonRetryableError(`Payment failed: ${paymentResult.failureReason}`);} -
Arrange Shipping
If payment and inventory checks are successful, proceed to arrange shipping.
// Inside the async (flow) => { ... }await flow.do('arrange shipping', async () => {if (!inventoryStatus.available) {// Handle out-of-stock scenario - this might involve notifications or backorder logicflow.warn('Items not available for order:', validatedOrder.orderId);throw new NonRetryableError('Items not available for shipping.');}console.log('Arranging shipping for order:', validatedOrder.orderId);// Replace with actual shipping arrangement logicreturn arrangeShipment(validatedOrder.shippingAddress, validatedOrder.items);}); -
Send Order Confirmation
Finally, send a confirmation to the customer.
// Inside the async (flow) => { ... }await flow.do('send order confirmation', async () => {console.log('Sending confirmation for order:', validatedOrder.orderId);// Replace with actual notification logicawait sendConfirmationEmail(validatedOrder.customerId, validatedOrder.orderId, { paymentResult, inventoryStatus });});return {orderId: validatedOrder.orderId,status: 'ORDER_PROCESSING_COMPLETED',paymentId: paymentResult.transactionId};
import * as v from '@identity-flow/sdk/valibot';import { NonRetryableError, defineWorkflow } from '@identity-flow/sdk';
// --- Mock external functions for demonstration ---async function processPayment(customerId: string, amount: number) { console.log(`Processing payment of ${amount} for customer ${customerId}`); // Simulate payment gateway call if (Math.random() < 0.1) return { success: false, failureReason: 'Insufficient funds' }; return { success: true, transactionId: 'txn-' + Math.random().toString(36).substring(7) };}async function checkInventoryAvailability(items: any[]) { console.log( 'Checking inventory for items:', items.map((i) => i.productId), ); // Simulate inventory check return { available: Math.random() > 0.05 }; // 95% chance items are available}async function arrangeShipment(address: any, items: any[]) { console.log('Arranging shipment to:', address.city, 'for items:', items.length);}async function sendConfirmationEmail(customerId: string, orderId: string, details: any) { console.log(`Sending order confirmation for ${orderId} to customer ${customerId}`);}// --- End mock functions ---
const OrderInputSchema = v.object({ orderId: v.string(), customerId: v.string(), items: v.array(v.object({ productId: v.string(), quantity: v.number() })), totalAmount: v.number(), shippingAddress: v.object({ street: v.string(), city: v.string(), zip: v.string() }),});
export default defineWorkflow( 'order-processing-example', { schema: OrderInputSchema, retries: { limit: 3, delay: '30 seconds', backoff: 'exponential' } }, async (flow) => { flow.log('Starting order processing for:', flow.params.orderId);
const validatedOrder = await flow.do('validate order business rules', async () => { if (!flow.params.items?.length) { throw new NonRetryableError('Order must contain items'); } flow.log('Order business rules validated for:', flow.params.orderId); return flow.params; });
const [paymentResult, inventoryStatus] = await Promise.all([ flow.do('process payment', async () => { flow.log('Processing payment for order:', validatedOrder.orderId); return processPayment(validatedOrder.customerId, validatedOrder.totalAmount); }), flow.do('check inventory', async () => { flow.log('Checking inventory for order:', validatedOrder.orderId); return checkInventoryAvailability(validatedOrder.items); }), ]);
if (!paymentResult.success) { flow.error('Payment failed for order:', validatedOrder.orderId, paymentResult.failureReason); throw new NonRetryableError(`Payment failed: ${paymentResult.failureReason}`); } flow.log( 'Payment successful for order:', validatedOrder.orderId, 'TxnID:', paymentResult.transactionId, );
await flow.do('arrange shipping', async () => { if (!inventoryStatus.available) { flow.warn('Items not available for order:', validatedOrder.orderId); throw new NonRetryableError('Items not available for shipping.'); } flow.log('Arranging shipping for order:', validatedOrder.orderId); return arrangeShipment(validatedOrder.shippingAddress, validatedOrder.items); }); flow.log('Shipping arranged for order:', validatedOrder.orderId);
await flow.do('send order confirmation', async () => { flow.log('Sending confirmation for order:', validatedOrder.orderId); await sendConfirmationEmail(validatedOrder.customerId, validatedOrder.orderId, { paymentResult, inventoryStatus, }); }); flow.log('Order confirmation sent for:', validatedOrder.orderId);
return { orderId: validatedOrder.orderId, status: 'ORDER_PROCESSING_COMPLETED', paymentId: paymentResult.transactionId, }; },); Document Approval Example Learn about workflows with timeouts and multiple reviewers.
Parallel Processing Dive deeper into concurrent step execution.
Error Handling Guide Master strategies for managing failures.