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 7 options, which are listed below.
Name | Description | Default | Type |
---|---|---|---|
expression | Required Expression to configure the maximum number of messages to throttle per request. | ExpressionDefinition | |
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 | |
timePeriodMillis | Sets the time period during which the maximum request count is valid for. | 1000 | String |
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 |
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 |
description | Sets the description of this node. | 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.