Workshop 7: Workflow Input/Output

Advanced Data Modeling Patterns

Create workflows that handle complex input parameters and return rich output data structures


What we want to build

Create workflows that handle complex input parameters and return rich output data structures.

This lesson focuses on advanced data modeling and input validation patterns.


Expecting Result

By the end of this workshop, you'll have:

  • A workflow that accepts complex input objects
  • Proper input validation before processing
  • Rich output objects with detailed results
  • Data transformation patterns between workflow and activities

Code Steps

Step 1: Create Input Data Classes

data class OrderRequest(
    val customerId: String,
    val items: List<OrderItem>,
    val shippingAddress: Address,
    val paymentMethod: PaymentMethod
)

data class OrderItem(
    val productId: String,
    val quantity: Int,
    val unitPrice: BigDecimal
)

Build structured, complex input objects for realistic business scenarios


More Input Data Classes

data class Address(
    val street: String,
    val city: String,
    val state: String,
    val zipCode: String,
    val country: String
)

enum class PaymentMethod {
    CREDIT_CARD, DEBIT_CARD, PAYPAL, BANK_TRANSFER
}

Use enums and structured objects for type safety


Step 2: Create Output Data Classes

data class OrderResult(
    val orderId: String,
    val status: OrderStatus,
    val totalAmount: BigDecimal,
    val estimatedDelivery: LocalDate,
    val trackingInfo: TrackingInfo?,
    val processingSteps: List<ProcessingStep>
)

enum class OrderStatus {
    PROCESSING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED
}

Rich output objects provide comprehensive result information


Additional Output Classes

data class TrackingInfo(
    val trackingNumber: String,
    val carrier: String,
    val estimatedDelivery: LocalDate
)

data class ProcessingStep(
    val stepName: String,
    val status: String,
    val timestamp: LocalDateTime,
    val details: Map<String, Any> = emptyMap()
)

Include audit trail and tracking information for observability


Step 3: Implement Order Processing Workflow

@WorkflowInterface
interface OrderProcessingWorkflow {
    @WorkflowMethod
    fun processOrder(orderRequest: OrderRequest): OrderResult
}

class OrderProcessingWorkflowImpl : OrderProcessingWorkflow {

    override fun processOrder(orderRequest: OrderRequest): OrderResult {
        // Validate inputs
        validateOrderRequest(orderRequest)

        // Process through activities
        val validation = validationActivity.validateOrder(orderRequest)
        val pricing = pricingActivity.calculateTotal(orderRequest.items)
        // Continued on next slide...
    }
}

Complete Workflow Implementation

    override fun processOrder(orderRequest: OrderRequest): OrderResult {
        // Validate inputs
        validateOrderRequest(orderRequest)

        // Process through activities
        val validation = validationActivity.validateOrder(orderRequest)
        val pricing = pricingActivity.calculateTotal(orderRequest.items)
        val payment = paymentActivity.processPayment(orderRequest.paymentMethod, pricing.total)
        val fulfillment = fulfillmentActivity.createShipment(orderRequest)

        return OrderResult(
            orderId = generateOrderId(),
            status = OrderStatus.CONFIRMED,
            totalAmount = pricing.total,
            estimatedDelivery = fulfillment.estimatedDelivery,
            trackingInfo = fulfillment.trackingInfo,
            processingSteps = listOf(validation.step, pricing.step, payment.step, fulfillment.step)
        )
    }

Input Validation Implementation

private fun validateOrderRequest(orderRequest: OrderRequest) {
    require(orderRequest.customerId.isNotBlank()) { 
        "Customer ID is required" 
    }
    require(orderRequest.items.isNotEmpty()) { 
        "Order must contain at least one item" 
    }
    require(orderRequest.items.all { it.quantity > 0 }) { 
        "All items must have positive quantity" 
    }
    require(orderRequest.items.all { it.unitPrice > BigDecimal.ZERO }) { 
        "All items must have positive price" 
    }
}

Always validate inputs early to fail fast with clear error messages


How to Run

Test with complex input data:

val orderRequest = OrderRequest(
    customerId = "customer123",
    items = listOf(
        OrderItem("product1", 2, BigDecimal("29.99")),
        OrderItem("product2", 1, BigDecimal("49.99"))
    ),
    shippingAddress = Address("123 Main St", "Anytown", "CA", "12345", "US"),
    paymentMethod = PaymentMethod.CREDIT_CARD
)

val result = workflow.processOrder(orderRequest)
println("Order processed: ${result.orderId}")
println("Status: ${result.status}")
println("Total: $${result.totalAmount}")
println("Estimated delivery: ${result.estimatedDelivery}")

Expected Output

Order processed: order_abc123456
Status: CONFIRMED
Total: $109.97
Estimated delivery: 2024-01-15
Processing steps:
  1. Validation: COMPLETED at 2024-01-10T10:00:00
  2. Pricing: COMPLETED at 2024-01-10T10:00:05
  3. Payment: COMPLETED at 2024-01-10T10:00:10
  4. Fulfillment: COMPLETED at 2024-01-10T10:00:15

Rich, detailed output provides complete transaction context


Key Patterns Demonstrated

Input Design:

  • Structured objects with clear relationships
  • Type safety through enums and data classes
  • Early validation with descriptive error messages

Output Design:

  • Comprehensive results with audit trail
  • Status tracking through the entire process
  • Rich metadata for debugging and monitoring

Data Transformation:

  • Clean mapping between input and activity parameters
  • Result aggregation from multiple activities

💡 Key Takeaways

What You've Learned:

  • Complex input modeling with nested data structures
  • Input validation patterns for robust error handling
  • Rich output design with comprehensive result information
  • Data transformation strategies between workflows and activities
  • Type safety through proper use of data classes and enums
  • Observability through detailed processing steps

🚀 Next Steps

You now master advanced workflow data patterns!

Ready for:

  • Activity retry and timeout strategies
  • Error handling and compensation patterns
  • Workflow signals and queries
  • Production deployment patterns

Let's build bulletproof distributed systems! 🎉

results matching ""

    No results matching ""