Skip to main content

Hierarchical Execution in WSL

This guide provides a comprehensive overview of hierarchical execution in the Workflow Specification Language (WSL), covering both regular WSL and SimplifiedWSL syntax.

Table of Contents

  1. Overview
  2. Architecture
  3. Workflow Types
  4. Context Sharing
  5. Regular WSL Syntax
  6. SimplifiedWSL Syntax
  7. Examples
  8. Best Practices

Overview

Hierarchical execution allows you to organize workflows into three levels:

  • Solutions - Top-level orchestration of features and workflows
  • Features - Mid-level orchestration of workflows
  • Workflows - Low-level execution of actions

All levels share the same WorkerSessionContext, enabling seamless data flow across the entire execution hierarchy.

Architecture

Execution Hierarchy

┌─────────────────────────────────────┐
│ Solution │
│ - Orchestrates features/workflows │
│ - Highest level of abstraction │
└───────────────┬─────────────────────┘
│ Shared Context

┌─────────────────────────────────────┐
│ Feature │
│ - Orchestrates workflows │
│ - Groups related functionality │
└───────────────┬─────────────────────┘
│ Shared Context

┌─────────────────────────────────────┐
│ Workflow │
│ - Executes actions │
│ - Contains states and transitions │
└─────────────────────────────────────┘

Runner Architecture

The engine provides three modular runners:

  1. SolutionRunner - Executes solution-type workflows

    • Can call features and workflows
    • Loads .wsl or .swsl files from disk
  2. FeatureRunner - Executes feature-type workflows

    • Can call workflows
    • Loads .wsl or .swsl files from disk
  3. WorkflowRunner - Executes workflow-type workflows

    • Executes actions
    • Loads .wsl or .swsl files from disk

Workflow Types

Solution

Purpose: Orchestrate features and workflows at the highest level

Use Cases:

  • Complete business solutions
  • Multi-feature applications
  • System-wide orchestration

Can Call:

  • Features
  • Workflows
  • Actions

Feature

Purpose: Group related workflows into cohesive features

Use Cases:

  • Feature modules (e.g., payment processing)
  • Subsystem orchestration
  • Reusable functionality groups

Can Call:

  • Workflows
  • Actions

Workflow

Purpose: Execute sequences of actions

Use Cases:

  • Individual business processes
  • Data transformations
  • Service integrations

Can Call:

  • Actions only

Context Sharing

All hierarchical components share the same WorkerSessionContext, which provides:

  • Persistent Data: Values set in one component are accessible in all others
  • Session State: Track execution state across the hierarchy
  • Result Passing: Pass results between components seamlessly

Example Context Usage

// In a workflow - set a value
context["user_id"] = "12345"
context["payment_amount"] = 100.00

// In a subsequent workflow or feature - access the value
userId := context["user_id"] // "12345"
amount := context["payment_amount"] // 100.00

Regular WSL Syntax

Solution Declaration

module payment_solution

solution complete_payment {
start: Initialize

state Initialize {
action context/Set(key: "solution_id", value: "sol_001")
on success -> CallPaymentFeature
}

state CallPaymentFeature {
action workflow/Call(name: "payment_feature")
on success -> CallNotificationFeature
}

state CallNotificationFeature {
action workflow/Call(name: "notification_feature")
on success -> Complete
}

state Complete {
action services/common/Response(message: "Solution completed")
end ok
}
}

Feature Declaration

module payment_processing

feature payment_feature {
start: ValidatePayment

state ValidatePayment {
action workflow/Call(name: "validate_payment_workflow")
on success -> ProcessPayment
}

state ProcessPayment {
action workflow/Call(name: "process_payment_workflow")
on success -> Complete
}

state Complete {
action services/common/Response(message: "Feature completed")
end ok
}
}

Workflow Declaration

module payment_validation

workflow validate_payment_workflow {
start: CheckAmount

state CheckAmount {
action payment/ValidateAmount(amount: $context.payment_amount)
on success -> CheckAccount
}

state CheckAccount {
action payment/ValidateAccount(userId: $context.user_id)
end ok
}
}

SimplifiedWSL Syntax

SimplifiedWSL provides a streamlined syntax for hierarchical execution:

Solution (SimplifiedWSL)

module payment_solution

solution complete_payment

const {
solution_id: "sol_001",
timeout: 5000
}

def errors.HandleError(level: "critical") as errorHandler -> .

# Initialize context
context.Set(key: "solution_id", value: $constants.solution_id) ->

# Call payment feature
payment.ProcessFeature() <- errorHandler ->

# Call notification feature
notification.SendFeature() <- errorHandler ->

# Complete
services/common.Response(message: "Solution completed") -> .

Feature (SimplifiedWSL)

module payment_processing

feature payment_feature

const {
max_retries: 3
}

def errors.LogError() as errorHandler -> .

# Validate payment
payment.Validate() <- errorHandler ->

# Process payment
payment.Process(retries: $constants.max_retries) <- errorHandler ->

# Complete
services/common.Response(message: "Feature completed") -> .

Workflow (SimplifiedWSL)

module payment_validation

workflow validate_payment

def errors.OnError() as errorHandler -> .

# Check amount
payment.ValidateAmount(amount: $context.payment_amount) <- errorHandler ->

# Check account
payment.ValidateAccount(userId: $context.user_id) <- errorHandler -> .

Examples

Complete Hierarchical Example

1. Solution File (solution_example.swsl)

module ecommerce_solution

solution complete_checkout

const {
solution_name: "E-commerce Checkout",
version: "1.0.0"
}

def errors.HandleCritical(level: "critical") as criticalError -> .

# Set solution context
context.Set(key: "solution_name", value: $constants.solution_name) ->

# Call payment feature
payment.ProcessCheckout() <- criticalError ->

# Call notification feature
notification.NotifyUser() <- criticalError ->

# Finalize
services/common.Response(message: "Checkout completed", status: "success") -> .

2. Payment Feature File (feature_payment.swsl)

module payment_processing

feature payment_checkout

const {
timeout: 5000,
retries: 3
}

def errors.LogError(level: "error") as errorHandler -> .

# Validate payment
payment.ValidatePayment(timeout: $constants.timeout) <- errorHandler ->

# Process payment
payment.ProcessPayment(retries: $constants.retries) <- errorHandler ->

# Send receipt
payment.SendReceipt() <- errorHandler -> .

3. Notification Feature File (feature_notification.swsl)

module notification_processing

feature notification_service

def errors.LogError(level: "error") as errorHandler -> .

# Prepare notification
notification.Prepare(userId: $context.user_id) <- errorHandler ->

# Send notification
notification.Send(message: "Payment processed successfully") <- errorHandler -> .

4. Workflow Files

Validate Payment Workflow (workflow_validate.swsl):

module payment_validation

workflow validate_payment

def errors.OnError() as errorHandler -> .

payment.CheckAmount(amount: $context.payment_amount) <- errorHandler ->
payment.CheckBalance(userId: $context.user_id) <- errorHandler -> .

Process Payment Workflow (workflow_process.swsl):

module payment_processing

workflow process_payment

def errors.OnError() as errorHandler -> .

payment.Charge(amount: $context.payment_amount) <- errorHandler ->
payment.UpdateBalance(userId: $context.user_id) <- errorHandler -> .

Execution Flow

When you execute the solution:

  1. Solution sets context and calls features
  2. Payment Feature validates and processes payment
  3. Notification Feature sends notifications
  4. All components share the same context
  5. Errors propagate up through error handlers

Best Practices

1. Clear Separation of Concerns

  • Solutions: High-level business processes
  • Features: Cohesive functional modules
  • Workflows: Specific tasks

2. Context Management

# Set values early in the hierarchy
context.Set(key: "user_id", value: "12345") ->
context.Set(key: "timestamp", value: $datetime.now()) ->

# Use values in lower levels
payment.Process(userId: $context.user_id, timestamp: $context.timestamp) ->

3. Error Handling

# Define error handlers at each level
def errors.SolutionError(severity: "critical") as solutionError -> .
def errors.FeatureError(severity: "high") as featureError -> .
def errors.WorkflowError(severity: "medium") as workflowError -> .

# Use appropriate handler for each component
payment.ProcessFeature() <- solutionError ->
payment.ValidateWorkflow() <- featureError ->
payment.CheckAction() <- workflowError -> .

4. File Organization

workflows/
├── solutions/
│ └── ecommerce_solution.swsl
├── features/
│ ├── payment_feature.swsl
│ └── notification_feature.swsl
└── workflows/
├── validate_workflow.swsl
└── process_workflow.swsl

5. Testing Strategy

  • Test workflows independently first
  • Test features with mock workflows
  • Test solutions with integration tests
  • Verify context sharing between levels

6. Naming Conventions

  • Solutions: *_solution (e.g., ecommerce_solution)
  • Features: *_feature (e.g., payment_feature)
  • Workflows: *_workflow or descriptive names (e.g., validate_payment)

Common Patterns

Sequential Execution

# Solution coordinates sequential features
feature:feature_one() ->
feature:feature_two() ->
feature:feature_three() -> .

Conditional Execution

Use regular WSL for complex conditions:

state ProcessPayment {
action workflow/Call(name: "process_payment")
on success when $context.amount > 100 -> SendReceipt
on success when $context.amount <= 100 -> Complete
}

Parallel Execution

Future enhancement - currently sequential only.

Troubleshooting

Context Not Shared

Issue: Values set in one component not accessible in another

Solution: Ensure all components use the same WorkerSessionContext instance

Workflow Not Found

Issue: Called workflow/feature file not found

Solution: Verify file naming matches call and files are in the correct directory

Type Mismatch

Issue: Calling feature from workflow level

Solution: Verify hierarchy: Solutions call features/workflows, Features call workflows, Workflows call actions

See Also