Layer 2: EIP Overview

Layer 2 is Priostack's Enterprise Integration Patterns (EIP) routing layer. It operates on top of the BPMN execution engine (Layer 1) to provide message-oriented integration primitives for complex, large-scale workflow scenarios.

When to use Layer 2: Use Layer 2 when you need to route, transform, aggregate, or filter messages between processes, systems, or services at a level above individual BPMN service tasks. If your routing logic is causing complexity in your BPMN diagrams, it's a sign that Layer 2 is the right abstraction.

Architecture Diagram


  External Systems / APIs · Messages (JSON/XML/binary)
         v
  ┌────────────────────────────────────────────────────────┐
  │                    LAYER 2: EIP                        │
  │                                                        │
  │  ┌─────────────┐     ┌─────────────┐                  │
  │  │  Message    │────►│  Message    │                  │
  │  │  Channel A  │     │  Router     │──► Channel B     │
  │  └─────────────┘     │  (FEEL)     │──► Channel C     │
  │                      └─────────────┘──► Channel D     │
  │                                                        │
  │  ┌─────────────┐     ┌─────────────┐                  │
  │  │  Splitter   │────►│  Pipeline   │                  │
  │  │  (fan-out)  │     │  (filter →  │                  │
  │  └─────────────┘     │   translate)│                  │
  │                      └─────────────┘                  │
  │                                                        │
  │  ┌─────────────┐     ┌─────────────┐                  │
  │  │  Aggregator │     │  Correlation│                  │
  │  │  (collect N)│     │  Context    │                  │
  │  └─────────────┘     │  (dedup)    │                  │
  │                      └─────────────┘                  │
  │                           │                           │
  │              ┌────────────▼────────────┐              │
  │              │   Message Endpoint      │              │
  │              │   (triggers BPMN start) │              │
  │              └────────────────────────┘              │
  └────────────────────────────────────────────────────────┘
                           │
                           v
              ┌────────────────────────┐
              │    LAYER 1: BPMN       │
              │    Execution Engine    │
              └────────────────────────┘
    

Patterns Reference

Message Channel

A named, typed conduit through which messages flow from producers to consumers. Channels decouple message sources from destinations. Each channel has a defined schema for the messages it carries.

// Configure a channel
{
  "name": "order-events",
  "schema": "application/json",
  "retention": "7d",
  "maxQueueDepth": 10000
}

Message Router

Routes incoming messages to one or more output channels based on FEEL expressions. The router evaluates conditions against the message payload and headers to determine the routing decision.

// Route by order amount
{
  "type": "router",
  "input": "order-events",
  "routes": [
    { "condition": "=amount > 10000", "output": "high-value-orders" },
    { "condition": "=amount > 1000",  "output": "standard-orders" },
    { "default": true,                "output": "small-orders" }
  ]
}

Aggregator

Collects a set of related messages and combines them into a single result message. The aggregator groups messages by a correlation key and emits a combined result when a completion condition is met (e.g., all N messages received, or a timeout expires).

// Aggregate all order lines before processing
{
  "type": "aggregator",
  "correlationKey": "=orderId",
  "completionCondition": "=count(messages) >= lineCount",
  "timeout": "PT5M",
  "output": "order-ready"
}

Correlation Context

Maintains a time-windowed deduplication context for messages. If the same message (identified by event ID or a FEEL key expression) is received multiple times within the window, only the first occurrence is processed. Subsequent duplicates are silently dropped.

// Deduplicate by payment transaction ID
{
  "type": "correlation-context",
  "key": "=transactionId",
  "window": "PT1H",
  "onDuplicate": "drop"
}

Pipeline

A multi-stage processing chain where each stage is either a filter (drops messages not matching a predicate) or a transformer (modifies message content). Stages are applied sequentially.

// Filter → validate → enrich pipeline
{
  "type": "pipeline",
  "stages": [
    { "filter": "=status != 'test'" },
    { "transform": "=context merge(message, { processedAt: now() })" },
    { "filter": "=amount > 0" }
  ],
  "output": "validated-orders"
}

Splitter

Takes a single message containing a list and emits one message per list item. Useful for fan-out scenarios where a batch message must be processed item by item.

// Split an order batch into individual orders
{
  "type": "splitter",
  "expression": "=orders",
  "correlationId": "=batchId",
  "output": "individual-orders"
}

Message Translator

Transforms a message from one schema to another using a FEEL context expression. Field names, types, and structure can be remapped. Used to bridge differences between upstream and downstream message formats.

// Translate from legacy order format to canonical format
{
  "type": "translator",
  "mapping": {
    "orderId":    "=legacy.order_no",
    "customerId": "=legacy.cust_id",
    "amount":     "=decimal(legacy.amount_cents / 100, 2)",
    "currency":   "=upper case(legacy.curr)"
  }
}

Message Filter

A simple single-stage filter that drops messages not matching a FEEL predicate. Equivalent to a one-stage Pipeline with a single filter step.

// Only pass orders from the EU region
{
  "type": "filter",
  "predicate": "=region = \"EU\" and currency in [\"EUR\", \"GBP\", \"CHF\"]",
  "onReject": "dead-letter"
}

Message Endpoint

Bridges Layer 2 channels to Layer 1 BPMN processes. When a message arrives on the input channel, the endpoint either starts a new process instance or correlates the message to an existing waiting instance (via a correlation key).

// Start a BPMN process for each order on the channel
{
  "type": "endpoint",
  "input": "validated-orders",
  "action": "start-process",
  "bpmnProcessId": "order-processing",
  "variableMapping": {
    "orderId":    "=message.orderId",
    "amount":     "=message.amount",
    "customerId": "=message.customerId"
  }
}

// Or correlate to a waiting Message Catch Event
{
  "type": "endpoint",
  "input": "payment-confirmed",
  "action": "correlate-message",
  "messageName": "payment-received",
  "correlationKey": "=message.orderId"
}

Integration with BPMN

Layer 2 patterns connect to Layer 1 processes through Message Endpoints. From the BPMN perspective, Layer 2 is transparent — a process simply waits at a Message Catch Event or is started by an external trigger. The routing and transformation logic lives entirely in Layer 2 configuration, keeping BPMN diagrams clean.

See the Architecture page for the full two-layer system diagram and how the layers interact.

Blog post: Read the EIP Pipelines in Priostack article for worked examples of building real integration scenarios with Layer 2 patterns.