Throttle
How can I throttle messages to ensure that a specific endpoint does not get overloaded, or we don’t exceed an agreed SLA with some external service?
Use a Throttler that controls the rate how many or fast messages are flowing to the endpoint.
Options
The Throttle eip supports 8 options, which are listed below.
Name | Description | Default | Type |
---|---|---|---|
description |
Sets the description of this node. |
String |
|
disabled |
Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime. |
false |
Boolean |
expression |
Required Expression to configure the maximum number of messages to throttle per request. |
ExpressionDefinition |
|
mode |
Sets the throttling mode to one of the available modes enumerated in ThrottlingMode. Enum values:
|
TotalRequests |
ThrottlingMode |
correlationExpression |
The expression used to calculate the correlation key to use for throttle grouping. The Exchange which has the same correlation key is throttled together. |
ExpressionSubElementDefinition |
|
executorService |
To use a custom thread pool (ScheduledExecutorService) by the throttler. |
ExecutorService |
|
asyncDelayed |
Enables asynchronous delay which means the thread will not block while delaying. |
false |
Boolean |
callerRunsWhenRejected |
Whether or not the caller should run the task when it was rejected by the thread pool. Is by default true. |
true |
Boolean |
rejectExecution |
Whether or not throttler throws the ThrottlerRejectedExecutionException when the exchange exceeds the request limit Is by default false. |
false |
Boolean |
timePeriodMillis |
Sets the time period during which the maximum request count is valid for. |
1000 |
String |
Using Throttle
The below example will throttle messages received on seda:a before being sent to mock:result ensuring that a maximum of 3 messages are sent during a running 10-seconds window slot.
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(3).timePeriodMillis(10000)
.to("mock:result");
<route>
<from uri="seda:a"/>
<throttle timePeriodMillis="10000">
<constant>3</constant>
</throttle>
<to uri="mock:result"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 3
timePeriodMillis: 10000
- to:
uri: mock:result
To use 10-seconds window we set the timePeriodMillis
to ten-thousand. The default value is 1000 (i.e. 1 second),
meaning that setting just throttle(3)
has the effect of setting the maximum number of requests per second.
To throttle by 50 requests per second, would look like this:
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(50)
.to("seda:b");
<route>
<from uri="seda:a"/>
<throttle>
<constant>50</constant>
</throttle>
<to uri="mock:result"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 50
- to:
uri: mock:result
Dynamically changing maximum requests per period
The Throttler uses an Expression
to configure the number of requests. In all the examples from above, we used
a constant. However, the expression can
be dynamic, such as determined from a message header from the current Exchange
.
At runtime Camel evaluates the expression and converts the result to a java.lang.Long
type.
In the example below we use a header from the message to determine the maximum requests per period.
If the header is absent, then the Throttler uses the old value. This allows you to only provide a header if the value is to be changed:
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(header("throttleValue")).timePeriodMillis(500)
.to("seda:b")
<route>
<from uri="seda:a"/>
<throttle timePeriodMillis="500">
<!-- use a header to determine how many messages to throttle per 0.5 sec -->
<header>throttleValue</header>
</throttle>
<to uri="seda:b"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
# use a header to determine how many messages to throttle per 0.5 sec
header: throttleValue
timePeriodMillis: 500
- to:
uri: seda:b
Asynchronous delaying
You can let the Throttler use non-blocking asynchronous delaying, which means Camel will use a scheduler to schedule a task to be executed in the future. The task will then continue routing. This allows the caller thread to not block and be able to service other messages, etc.
You enable asynchronous delaying using asyncDelayed
as shown:
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(100).asyncDelayed()
.to("seda:b");
<route>
<from uri="seda:a"/>
<throttle asyncDelayed="true">
<constant>100</constant>
</throttle>
<to uri="seda:b"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 100
asyncDelayed: true
- to:
uri: seda:b
Rejecting processing if rate limit hit
When a message is being throttled due the maximum request per limit has been reached, then the Throttler will by default wait until there is free space before continue routing the message.
Instead of waiting you can also configure the Throttler to reject the message by throwing ThrottlerRejectedExecutionException
exception.
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(100).rejectExecution(true)
.to("seda:b");
<route>
<from uri="seda:a"/>
<throttle timePeriodMillis="100" rejectExecution="true">
<constant>100</constant>
</throttle>
<to uri="seda:b"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 100
timePeriodMillis: 100
rejectExecution: true
- to:
uri: seda:b
Throttling per group
The Throttler will by default throttle all messages in the same group. However, it is possible to use a correlation expression to diving into multiple groups, where each group is throttled independently.
For example, you can throttle by a message header as shown in the following example:
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(100).correlationExpression(header("region"))
.to("seda:b");
<route>
<from uri="seda:a"/>
<throttle>
<constant>100</constant>
<correlationExpression>
<header>region</header>
</correlationExpression>
</throttle>
<to uri="seda:b"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 100
correlationExpression:
header: region
- to:
uri: seda:b
In the example above messages are throttled by the header with name region. So suppose there are regions for US, EMEA, and ASIA, then we have three different groups, that each are throttled by 100 messages per second.
Throttling Modes
Apache Camel comes with two distinct throttling modes to control and manage the flow of requests in their applications.
These modes address different aspects of request handling:
- Total Requests Mode
-
Throttles requests based on the total number of requests made within a defined unit of time. It regulates the overall traffic flow to prevent overwhelming the system with an excessive number of requests.
- Concurrent Connections Mode
-
Throttles requests by managing concurrent connections using a leaky bucket algorithm. This algorithm controls the rate at which requests are processed simultaneously, preventing system overload.
Default Mode
By default, Camel uses the Total Requests Mode as the default throttling mechanism.
This means that, unless specified otherwise, the framework regulates the flow of requests based on the total number of requests per unit of time.
Choosing Throttling Mode
Users can choose their preferred throttling mode using different approaches:
- DSL Methods
-
-
totalRequestsMode()
: Sets the total requests mode. -
concurrentRequestsMode()
: Sets the concurrent connections mode.
-
- Mode DSL Method
-
-
mode(String)
: Users can specify the throttling mode by passing eitherTotalRequests
orConcurrentRequests
as an argument.
-
For example, mode("ConcurrentRequests")
sets the throttling mode based on concurrent connections.
These options provide users with fine-grained control over how Camel manages the flow of requests, allowing them to choose the mode that best aligns with their specific application requirements.
-
Java
-
XML
-
YAML
from("seda:a")
.throttle(3).mode("ConcurrentRequests")
.to("mock:result");
<route>
<from uri="seda:a"/>
<throttle mode="ConcurrentRequests">
<constant>3</constant>
</throttle>
<to uri="mock:result"/>
</route>
- from:
uri: seda:a
steps:
- throttle:
expression:
constant: 3
mode: ConcurrentRequests
timePeriodMillis: 10000
- to:
uri: mock:result