Enterprise Integration Patterns
Overview
GoCamel implements the Enterprise Integration Patterns (EIP) from the classic book by Gregor Hohpe and Bobby Woolf.
Message Routing
Choice
Content-based routing with conditional branches.
Syntax:
When(expression)- Adds a conditional branchOtherwise()- Adds a default branchEndChoice()- Ends the Choice blockEnd()- Alternative method
Expression Operators:
| Operator | Description | Example |
|---|---|---|
== | Equal | ${header.type} == 'order' |
!= | Not equal | ${header.status} != 'error' |
> | Greater than | ${header.count} > 10 |
>= | Greater or equal | ${header.count} >= 10 |
< | Less than | ${header.price} < 100 |
<= | Less or equal | ${header.price} <= 100 |
&& | AND | a > 5 && b == 'x' |
|| | OR | a > 5 || b == 'y' |
Filter
Filter messages based on a condition. Exchanges that do not match are silently dropped (ErrStopRouting).
Throttle
Rate-limit exchange processing to at most N messages per time window. Exchanges that exceed the rate are delayed, not dropped, until the window resets.
Notes:
- Uses a fixed-window counter; for smoother behaviour use smaller windows
- Blocking: the goroutine sleeps until the window allows the exchange through
maxRequestsandtimePeriodmust be greater than zero; invalid values return an error instead of blocking indefinitely- If the exchange context is cancelled while waiting for the next window,
Processreturns an error
Delay
Pause exchange processing for a fixed or dynamically computed duration. The sleep respects context cancellation.
Notes:
- Blocking: the goroutine sleeps for the computed duration
- If the exchange context is cancelled during the sleep,
Processreturns an error - Return
0fromDelayFuncto skip the delay for a given exchange - Passing
niltoDelayFuncfails route construction;NewDelayerFunc(nil)remains constructible but returns a processing error instead of panicking
Content Enricher
Fetch additional data from an external resource and merge it into the current exchange.
How it works:
- A copy of the current exchange is sent to the enrichment URI
- The response is received
AggregationStrategy.Aggregate(original, response)merges the two- If no strategy is provided, the response body replaces the original body
Idempotent Consumer
Prevent duplicate messages from being processed.
How it works:
- Evaluates the expression to get a unique key.
- Checks if the key exists in the repository.
- If not present, adds the key eagerly (blocking concurrent duplicates) and proceeds.
- If present, stops routing (
ErrStopRouting). - If the exchange later fails downstream, the key is removed from the repository again
(via an exchange
Synchronization), so a redelivery of the same message is processed instead of being dropped — at-least-once semantics.
Repositories:
NewMemoryIdempotentRepository(): In-memory store (default).NewRedisIdempotentRepository(): Distributed store backed by Redis.- SQL-based repositories can be implemented via the
IdempotentRepositoryinterface.
Circuit Breaker
Protect routes from cascading failures when calling unstable external services.
States:
- Closed: Requests pass through. Failures are counted.
- Open: Requests fail immediately or go to fallback.
- Half-Open: After
OpenTimeout, a single trial request at a time probes the downstream service; concurrent requests are diverted to the fallback as if the circuit were still open. OnceSuccessThresholdsuccessful probes complete, the circuit closes. If a probe fails, it opens again.
Load Balancer
Distribute messages across multiple endpoints.
Strategies:
RoundRobin(): Circular distribution (default).Random(): Random distribution.Custom(strategy): Provide a custom implementation of theLoadBalancerStrategyinterface.
SEDA
Staged Event-Driven Architecture. Decouples producers and consumers using an internal queue (Go channel).
How it works:
- The producer sends a copy of the exchange to an internal queue.
- The producer returns immediately (non-blocking if queue is not full).
- One or more consumer workers read from the queue and process the exchange.
Parameters:
size: The capacity of the internal queue (default 1000).concurrentConsumers: The number of worker goroutines (default 1).
Invalid values (negative size, non-positive concurrentConsumers) fall back to the
defaults with a warning. Parameters are applied when the endpoint is first created;
later references to the same queue name reuse the existing endpoint.
Resequencer
Reorder messages that arrived out of order based on a sequence number or timestamp.
How it works:
- Evaluates the expression to get the sequence number.
- If the sequence is the next expected one, it’s processed immediately.
- If it’s a future sequence, it’s buffered and sorted.
- If a gap persists longer than the
Timeout, the resequencer skips the missing sequence and continues with the next available one in the buffer.
Notes:
- Messages are delivered downstream through the resequencer’s internal pipeline (the steps
between
Resequence(...)andEnd()). The original exchange stops there (ErrStopRouting), so steps placed afterEnd()never see out-of-order messages. - Delivery is serialized to guarantee ordering; downstream steps must not route back into the same resequencer.
- Duplicate or outdated sequence numbers are dropped (logged as warnings).
Claim Check
Reduce the size of messages by storing the payload in an external repository and passing only a reference (key).
Operations:
ClaimCheckPush: Stores the body and replaces it with a key. If no key is provided, one is generated.ClaimCheckPop: Retrieves the data by key, restores the body, and removes it from the repository.ClaimCheckGet: Retrieves the data by key and restores the body (keeps it in the repository).ClaimCheckDiscard: Removes the data from the repository without restoring it.
Multicast
Send a copy of the message to multiple destinations.
With Parallel Processing:
With Strategy:
Message Transformation
Splitter
Divide a message into parts.
With Aggregation:
Exchange Properties during Split:
| Property | Type | Description |
|---|---|---|
CamelSplitIndex | int | Current index (0-based) |
CamelSplitSize | int | Total number of parts |
CamelSplitComplete | bool | Last part indicator |
These properties are branch-scoped
They describe one part, not the whole message, and are removed when the
aggregated result is published back onto the parent exchange. A processor
placed after the Split does not see CamelSplitComplete=true left over
from the last part, and a nested Split does not overwrite the bookkeeping
of the enclosing one. The same rule applies to CamelMulticast*,
CamelRecipientList* and CamelRoutingSlip*.
A []byte body is not a collection
Splitting a []byte body yields a single part, matching Apache Camel,
which does not split byte[]. Treating it as a list produced one exchange
per byte — a 10 KB payload became 10 000 exchanges. To divide binary
content deliberately, split on a decoded value instead:
Aggregator
Combine multiple messages into one.
Aggregation Strategy:
Completion Conditions:
| Method | Description |
|---|---|
SetCompletionSize(n) | Complete after n messages |
SetCompletionTimeout(ms) | Complete after timeout |
SetCompletionPredicate(fn) | Complete when predicate returns true |
Storage Options:
Transformer
Transform message content.
Transform
A dedicated message transformation EIP that modifies the message body dynamically using a custom Go function or a Simple language expression.
Messaging Systems
Pipeline
Sequential processing within multicast.
ToD (Dynamic To)
Send to dynamically computed endpoint.
Recipient List
Send to multiple recipients computed at runtime.
Dynamic Router
Route an exchange through a sequence of endpoints resolved dynamically by calling a control function after each step.
Routing ends when the function returns an empty string or nil.
How it works:
- Calls the control function/expression.
- If result is non-empty, sends exchange to that URI.
- Propagates output to input and repeats from step 1.
Routing Slip
Route an exchange through a dynamic sequence of endpoints. Unlike Recipient List, each step receives the output from the previous step.
Exchange Properties during Routing Slip:
| Property | Type | Description |
|---|---|---|
CamelRoutingSlipIndex | int | Current step index (0-based) |
CamelRoutingSlipSize | int | Total number of routing steps |
CamelRoutingSlipComplete | bool | Last step indicator |
Control Flow
Stop
Stop routing without error.
Note: Subsequent processors won’t be executed.
Loop
Iterate a route segment a static or dynamic number of times.
Exchange Properties during Loop:
| Property | Type | Description |
|---|---|---|
CamelLoopIndex | int | Current iteration index (0-based) |
CamelLoopSize | int | Total number of loop iterations |
CamelLoopComplete | bool | Boolean indicating if this is the last iteration |
Message Headers
SetHeader
RemoveHeader
Exchange Properties
SetProperty
Exchange-scoped variables (not in message).
RemoveProperty
Error Handling
Do-Try-Catch-Finally
Structured error handling within a route.
How it works:
- Executes the processors in the
DoTryblock. - If an error occurs, it searches for a matching
DoCatchblock (empty string matches any error). - If a match is found, the error is considered “handled” and routing continues after the
DoTryblock (unless the catch block itself fails). - The
DoFinallyblock is always executed, regardless of whether an error occurred or was caught.
Transactions & Sagas
Saga
The Saga EIP provides a mechanism to coordinate a series of local transactions across distributed services without locking databases. It defines a set of actions and their corresponding compensating actions (rollbacks).
If any action in the Saga block fails or returns an error, the Saga orchestrator automatically triggers the compensating steps for all completed actions in reverse order (LIFO - Last In, First Out).
You can also use custom Go functions for actions and compensations directly using ActionFunc:
Message Tracking & Diagnostics
Message History
The Message History EIP enables tracing the chronological journey of a message as it flows through the various route nodes and processors.
To enable tracking for a route, invoke .EnableMessageHistory() on your route builder. You can then retrieve and inspect the history using gocamel.GetMessageHistory(exchange).
EIP Pattern Summary
| Pattern | Category | Description |
|---|---|---|
| Choice | Routing | Content-based routing |
| Filter | Routing | Conditional filtering |
| Idempotent Consumer | Routing | Prevent duplicate messages |
| Circuit Breaker | Routing | Resilience pattern for failures |
| Load Balancer | Routing | Load distribution across endpoints |
| Dynamic Router | Routing | Dynamic decision-based routing |
| Resequencer | Routing | Reorder messages by sequence |
| Claim Check | Routing | Store payload and pass reference |
| Throttle | Routing | Rate limiting |
| Delay | Routing | Pause before next step |
| Multicast | Routing | Multiple destinations |
| Recipient List | Routing | Dynamic recipient routing |
| Routing Slip | Routing | Dynamic sequential routing |
| Wire Tap | Routing | Async fire-and-forget copy |
| Split | Transformation | Message splitting |
| Aggregate | Transformation | Message aggregation |
| Content Enricher | Transformation | Enrich with external data |
| Transform | Transformation | Content transformation |
| ToD | Endpoint | Dynamic endpoint |
| Stop | Control | Stop routing |
| DoTry | Control | Try-Catch-Finally error handling |
| SetHeader | Headers | Header manipulation |
| SetProperty | Properties | Exchange properties |
| Loop | Control | Iterate with static/dynamic counter |
| Saga | Control | Saga transactional pattern |
| Message History | Diagnostics | Track message processing trace |