Docs
Wave Flow
Priority-Based Traffic Protection

Priority-Based Traffic Protection

Priority-based traffic protection is Wave Flow's core mechanism for protecting critical services under load. Instead of treating all traffic equally, Wave Flow classifies each request into one of four priority tiers and makes intelligent decisions about which requests to serve and which to shed (reject).

The Four Priority Classes

Wave Flow uses a fixed hierarchy of four priority classes, ordered from highest to lowest:

1. CRITICAL - Never Shed

Purpose: Protect absolutely mission-critical traffic that must never be rejected, regardless of system load.

When to Use:

  • Direct revenue operations (checkout, payment processing)
  • Critical write operations (order submission, account creation)
  • Authentication and authorization flows
  • Downstream service dependencies that would cause cascading failures

Shedding Behavior: Always set to Disabled (never shed)

Examples:

  • POST /checkout/submit - Final checkout submission
  • POST /api/v1/payments - Payment processing
  • POST /api/v1/auth/login - User authentication
  • POST /api/v1/orders - Order creation
🚫

Never Shed CRITICAL Traffic

If your CRITICAL class is being shed, your system is fundamentally under-provisioned. Wave Flow cannot protect you from complete infrastructure failure — it can only intelligently prioritize traffic during temporary capacity constraints.

Solutions:

  • Scale infrastructure immediately (add nodes/pods)
  • Review resource requests and limits
  • Check for infrastructure issues (node failures, network problems)
  • Consider emergency shedding of IMPORTANT/MODERATE traffic

2. IMPORTANT - Shed Only Under Extreme Load

Purpose: Protect high-value traffic that is important but can tolerate rare failures during extreme overload scenarios.

When to Use:

  • Paid/premium user traffic
  • Real-time dashboard and monitoring
  • Critical read operations (order status, account balance)
  • Non-critical write operations (profile updates, preferences)

Shedding Behavior: Set to Auto (shed only when necessary)

Examples:

  • X-User-Tier: enterprise header (enterprise customers)
  • GET /api/v1/orders/{id} - Order status check
  • POST /api/v1/support/tickets - Support ticket creation
  • GET /api/v1/dashboard - User dashboard

When IMPORTANT Traffic Gets Shed:

  • System is already rejecting MODERATE and BULK traffic
  • Backend services are at >95% capacity
  • Response latencies are spiking to unacceptable levels
  • System is on the verge of complete failure without shedding

3. MODERATE - Shed Proactively

Purpose: General-purpose traffic that is valuable but can be degraded to protect higher-priority classes.

When to Use:

  • Product browsing and catalog viewing
  • Search and filtering operations
  • Free tier / non-paying user traffic
  • Less critical read operations

Shedding Behavior: Set to Auto (shed before IMPORTANT traffic is impacted)

Examples:

  • GET /products - Product listing
  • GET /search?q=shoes - Product search
  • GET /api/v1/recommendations - Recommendations (if moderately important)
  • X-User-Tier: free header (free tier users)

When MODERATE Traffic Gets Shed:

  • System is at 80-90% capacity
  • Response latencies are increasing
  • BULK traffic is already being heavily shed
  • System needs headroom to handle CRITICAL/IMPORTANT traffic

4. BULK - Shed Aggressively

Purpose: Low-priority traffic that provides nice-to-have features but can be shed freely to protect capacity.

When to Use:

  • Machine learning recommendations and personalization
  • Analytics and tracking
  • Prefetching and caching
  • Non-essential background operations
  • Internal testing traffic

Shedding Behavior: Set to Auto (shed first and most aggressively)

Examples:

  • GET /recommendations - ML-based recommendations
  • POST /api/v1/analytics - Analytics events
  • GET /similar-items - Related product suggestions
  • GET /static/prefetch/* - Prefetch requests

When BULK Traffic Gets Shed:

  • System is at >70% capacity
  • Any sign of resource constraint
  • Proactively to keep headroom for higher priorities

Match Rules: Traffic Classification

Match rules define how Wave Flow classifies incoming requests into priority classes. Each priority class can have multiple match rules, evaluated in order until a match is found.

Rule Components

Each match rule consists of three optional components (at least one must be specified):

1. HTTP Headers

Match based on request header name and value.

Format:

headers:
  - name: "X-User-Type"
    value: "premium"
  - name: "X-API-Key"
    value: "enterprise-key-12345"

Common Use Cases:

  • User tier classification (X-User-Type, X-Subscription-Tier)
  • API client identification (X-API-Client, User-Agent)
  • Internal vs. external traffic (X-Internal-Request: true)
  • Feature flags (X-Beta-Feature: enabled)

Matching Behavior:

  • Exact string match (case-sensitive)
  • All headers in a rule must match (AND logic)
  • Use separate rules for OR logic

2. URL Path Prefixes

Match based on URL path prefix.

Format:

paths:
  - prefix: "/checkout/"
  - prefix: "/api/v1/payments"
  - prefix: "/admin"

Common Use Cases:

  • Endpoint-based priority (/checkout/* is CRITICAL, /search/* is MODERATE)
  • API versioning (/api/v1/* vs. /api/v2/*)
  • Admin vs. user traffic (/admin/* vs. /app/*)
  • Public vs. authenticated endpoints

Matching Behavior:

  • Prefix match (not exact match)
  • /checkout/ matches /checkout/step1, /checkout/submit, etc.
  • Order matters: more specific prefixes should come first

3. HTTP Methods

Match based on HTTP method.

Format:

methods:
  - "POST"
  - "PUT"
  - "DELETE"

Common Use Cases:

  • Protect write operations (POST, PUT, DELETE) over reads (GET)
  • Critical mutations vs. safe reads
  • Bulk import operations

Matching Behavior:

  • Exact string match (case-insensitive)
  • Multiple methods in a rule are OR logic (any match succeeds)

Match Rule Evaluation Order

When a request arrives, Wave Flow evaluates priority classes in this order:

  1. CRITICAL class rules
  2. IMPORTANT class rules
  3. MODERATE class rules
  4. BULK class rules

Within each class, rules are evaluated:

  • If ANY rule matches → request is classified to that class
  • If NO rule matches → continue to next priority class
  • If no class matches → defaults to BULK (lowest priority)

Default to BULK for Unmatched Traffic

Any traffic that doesn't match any rule is automatically classified as BULK (lowest priority). This ensures that even unexpected traffic patterns don't accidentally get CRITICAL priority.

To explicitly protect unknown traffic, create a catch-all rule in the MODERATE or IMPORTANT class.

Example: E-Commerce Priority Configuration

CRITICAL:
  shed: disabled
  match_rules:
    # Checkout flow
    - paths:
        - prefix: "/checkout/"
      methods: ["POST", "PUT"]
    # Payment processing
    - paths:
        - prefix: "/api/v1/payments"
    # Order submission
    - paths:
        - prefix: "/api/v1/orders"
      methods: ["POST"]
    # Authentication
    - paths:
        - prefix: "/api/v1/auth"
 
IMPORTANT:
  shed: auto
  match_rules:
    # Premium users (all traffic)
    - headers:
        - name: "X-User-Tier"
          value: "premium"
    # Cart operations
    - paths:
        - prefix: "/cart/"
    # Order status checks
    - paths:
        - prefix: "/api/v1/orders"
      methods: ["GET"]
    # User profile
    - paths:
        - prefix: "/api/v1/users/profile"
 
MODERATE:
  shed: auto
  match_rules:
    # Product browsing
    - paths:
        - prefix: "/products/"
    # Search
    - paths:
        - prefix: "/search"
    # Inventory checks
    - paths:
        - prefix: "/api/v1/inventory"
      methods: ["GET"]
 
BULK:
  shed: auto
  match_rules:
    # Recommendations
    - paths:
        - prefix: "/recommendations"
    # Similar products
    - paths:
        - prefix: "/similar-items"
    # Analytics tracking
    - paths:
        - prefix: "/api/v1/analytics"
    # Static assets
    - paths:
        - prefix: "/static/"

Shedding Strategies

Each priority class has a shedding strategy that determines when and how aggressively traffic is rejected.

Disabled - Never Shed

Behavior: Traffic in this class is never shed, regardless of system load.

When to Use: CRITICAL class only (revenue-critical, must-succeed operations)

Configuration:

shed: disabled

Impact:

  • 100% of requests are allowed through
  • No automatic protection — you rely on infrastructure capacity
  • If system fails, CRITICAL traffic fails too
⚠️

Resource Exhaustion Risk

Setting all classes to "Disabled" defeats the purpose of Wave Flow. Always have at least MODERATE and BULK set to "Auto" to provide system protection.

Auto - Shed Based on Load

Behavior: Traffic is shed automatically when the system is under load. The threshold and aggressiveness depend on the priority class:

  • BULK: Shed aggressively (first to shed, highest rejection rate)
  • MODERATE: Shed moderately (protect CRITICAL/IMPORTANT)
  • IMPORTANT: Shed conservatively (only under extreme load)

When to Use: IMPORTANT, MODERATE, and BULK classes

Configuration:

shed: auto

How It Works:

Wave Flow monitors backend service health indicators:

  • Response latencies (P95, P99)
  • Error rates (5xx responses)
  • Resource utilization (CPU, memory)
  • Concurrent request counts

When load increases:

  1. 70-80% capacity: Start shedding BULK traffic
  2. 80-90% capacity: Increase BULK shedding, start shedding MODERATE
  3. 90-95% capacity: Heavy BULK shedding, moderate MODERATE shedding
  4. 95%+ capacity: Maximum BULK/MODERATE shedding, start shedding IMPORTANT

Auto Shedding is Dynamic

The exact thresholds are dynamically adjusted based on:

  • Historical traffic patterns
  • Service response time SLAs
  • Resource availability
  • Current error rates

This ensures shedding is neither too aggressive (degrading user experience unnecessarily) nor too conservative (failing to protect the system).

Force - Always Shed

Behavior: All traffic in this class is always rejected with HTTP 503.

When to Use:

  • Emergency traffic blocking (incident response)
  • Testing shedding behavior (verify clients handle 503 correctly)
  • Temporarily disable features (e.g., disable recommendations during incident)

Configuration:

shed: force

Impact:

  • 100% of requests are rejected
  • Useful for quickly disabling non-critical features during outage
  • Can be toggled without redeploying services

Example Use Case:

During a Black Friday incident where the database is overloaded:

  1. Set BULK class to Force → immediately reject all recommendations, analytics
  2. Set MODERATE class to Force → reject product browsing, search
  3. Keep IMPORTANT/CRITICAL as Auto → checkout and payments still work
  4. Database load drops by 70%, allowing critical operations to succeed
  5. Once incident is resolved, revert to Auto

Advanced Configuration Patterns

Pattern 1: Gradual Degradation (Recommended)

Configure each priority class with Auto shedding at different thresholds:

CRITICAL:
  shed: disabled  # Never shed
 
IMPORTANT:
  shed: auto      # Shed at 95%+ load
 
MODERATE:
  shed: auto      # Shed at 85%+ load
 
BULK:
  shed: auto      # Shed at 75%+ load

Benefits:

  • Graceful degradation as load increases
  • Protects most critical features longest
  • Users experience feature loss, not total outage

Pattern 2: User Tier-Based Priority

Classify traffic based on user subscription tier:

CRITICAL:
  shed: disabled
  match_rules:
    - headers:
        - name: "X-User-Tier"
          value: "enterprise"
 
IMPORTANT:
  shed: auto
  match_rules:
    - headers:
        - name: "X-User-Tier"
          value: "premium"
 
MODERATE:
  shed: auto
  match_rules:
    - headers:
        - name: "X-User-Tier"
          value: "basic"
 
BULK:
  shed: auto
  match_rules:
    - headers:
        - name: "X-User-Tier"
          value: "free"

Benefits:

  • Paying customers get priority
  • Free tier users shed first
  • Clear value proposition for upgrades

Pattern 3: Read/Write Separation

Protect write operations over read operations:

CRITICAL:
  shed: disabled
  match_rules:
    - methods: ["POST", "PUT", "DELETE", "PATCH"]
 
IMPORTANT:
  shed: auto
  match_rules:
    - methods: ["GET"]
      paths:
        - prefix: "/api/v1/orders"  # Important reads
        - prefix: "/api/v1/account"
 
MODERATE:
  shed: auto
  match_rules:
    - methods: ["GET"]  # All other reads

Benefits:

  • Data mutations are protected
  • Read-heavy traffic (browsing, searching) sheds first
  • Prevents database write contention

Pattern 4: Endpoint-Specific Priority

Different endpoints have different business value:

CRITICAL:
  shed: disabled
  match_rules:
    - paths:
        - prefix: "/checkout"    # $100 average order
        - prefix: "/payments"
 
IMPORTANT:
  shed: auto
  match_rules:
    - paths:
        - prefix: "/cart"        # $50 average cart value
        - prefix: "/wishlists"
 
MODERATE:
  shed: auto
  match_rules:
    - paths:
        - prefix: "/products"    # Browsing (low conversion)
        - prefix: "/reviews"
 
BULK:
  shed: auto
  match_rules:
    - paths:
        - prefix: "/recommendations"  # Nice-to-have

Benefits:

  • Aligned with business metrics
  • Clear ROI on protection (protect high-value transactions)

Best Practices

1. Start Conservative

Initial Configuration:

  • Set CRITICAL to Disabled
  • Set IMPORTANT to Auto (but expect 0 shedding)
  • Set MODERATE/BULK to Auto (expect shedding under load)

Gradually Tighten:

  • Monitor shedding rates for 1-2 weeks
  • If IMPORTANT is never shed, it's truly important
  • If MODERATE is heavily shed with no user complaints, it's correctly classified

2. Align with Business Metrics

Map Priority to Revenue:

  • CRITICAL: Direct revenue ($$$)
  • IMPORTANT: Indirect revenue ($$)
  • MODERATE: User experience ($)
  • BULK: Nice-to-have ($0)

Example:

  • Checkout ($100 avg order) → CRITICAL
  • Product page ($5 conversion value) → MODERATE
  • Recommendations ($0.50 conversion lift) → BULK

3. Test Shedding Behavior

Before Production:

  1. Create policy in staging environment
  2. Generate load with tools (hey, k6, JMeter)
  3. Verify BULK sheds first, CRITICAL never sheds
  4. Test client behavior when receiving HTTP 503

HTTP 503 Response Handling:

// Example: Retry logic for shedded requests
async function fetchWithRetry(url, options = {}) {
  const maxRetries = 3;
  const retryDelay = 1000; // 1 second
 
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
 
    if (response.status === 503) {
      // Request was shed — retry after delay
      await new Promise(resolve => setTimeout(resolve, retryDelay));
      continue;
    }
 
    return response;
  }
 
  throw new Error('Max retries exceeded');
}

4. Monitor and Alert

Key Metrics to Track:

  • CRITICAL rejection rate: Should always be 0% (alert if greater than 0%)
  • IMPORTANT rejection rate: Should be less than 1% (alert if greater than 5%)
  • MODERATE/BULK rejection rate: Acceptable, but track trends

Set Up Alerts:

# Example Prometheus alert
- alert: CriticalTrafficShed
  expr: waveflow_critical_rejected_total > 0
  for: 1m
  labels:
    severity: critical
  annotations:
    summary: "CRITICAL traffic is being shed"
    description: "Wave Flow is rejecting CRITICAL traffic. System is severely overloaded."

5. Document Priority Decisions

Create a Decision Matrix:

EndpointPriorityReasoningRevenue Impact
/checkout/submitCRITICALDirect revenue, $100 avg order$10K/hour
/cart/addIMPORTANTLeads to checkout, $50 cart value$5K/hour
/products/*MODERATEBrowsing, 2% conversion$500/hour
/recommendationsBULKML feature, 0.5% lift$50/hour

Benefits:

  • Align engineering and business teams
  • Justify priority decisions to stakeholders
  • Easier to onboard new engineers

Troubleshooting

Issue: All Traffic Being Shed

Symptoms:

  • Even CRITICAL traffic returns HTTP 503
  • All priority classes show 100% rejection rate

Causes:

  1. CRITICAL class set to "Force": Change to "Disabled"
  2. Match rules incorrect: CRITICAL class has no matching rules
  3. System completely overloaded: Infrastructure insufficient

Solutions:

  • Verify CRITICAL shedding strategy is "Disabled"
  • Check match rules cover expected traffic patterns
  • Scale infrastructure if genuinely overloaded

Issue: No Shedding Under Load

Symptoms:

  • System is overloaded (high latency, errors)
  • Wave Flow shows 0% rejection rate for all classes

Causes:

  1. All classes set to "Disabled": No shedding configured
  2. Load not reaching proxies: Traffic bypassing ingress gateway
  3. WASM module not deployed: Proxy filter configuration missing or misconfigured

Solutions:

  • Set MODERATE/BULK to "Auto"
  • Verify traffic flows through your ingress gateway or service mesh
  • Check WASM module is deployed:
    • For Istio: kubectl get envoyfilter -n istio-system
    • For other proxies: Check your proxy's WASM plugin configuration

Issue: Wrong Traffic Being Shed

Symptoms:

  • Important user traffic getting HTTP 503
  • Low-priority traffic succeeding

Causes:

  1. Match rules too broad: IMPORTANT class matches too much
  2. Match rules too narrow: IMPORTANT traffic not matching any rule (defaults to BULK)
  3. Header/path mismatch: Application not sending expected headers

Solutions:

  • Review match rules and adjust specificity
  • Add logging to see which class requests are matched to
  • Verify application sends expected headers (X-User-Tier, etc.)

Summary

Priority-based traffic protection is a powerful pattern for protecting critical services:

  • Four Priority Classes: CRITICAL (never shed), IMPORTANT (rare shed), MODERATE (proactive shed), BULK (aggressive shed)
  • Match Rules: HTTP headers, URL paths, HTTP methods determine classification
  • Shedding Strategies: Disabled (never), Auto (dynamic), Force (always)
  • Gradual Degradation: System sheds lower-priority traffic first, preserving critical features longest

By thoughtfully configuring priority classes and match rules, you can ensure your most important business functions remain available even during infrastructure failures or unexpected traffic spikes.

For implementation guidance, see the Getting Started Guide. For architectural context, see the Overview.