rbutenuth / rate-limiter

Apache License 2.0
1 stars 3 forks source link

Rate-limiter Module

The rate limiter module offers the feature to limit the performance of a flow or can introduce a fixed delay. It has been developed by C&A and codecentric.

Compared to a simple Thread.sleep() it has the advantage to hook into the asynchronous event mechanism of the Mule runtime: During wait, no thread is blocked. The behavior is similar to modules with an asynchronous implementation, e.g. http: While the request is handled by the remote system, no thread on the client side is blocked.

Rate limit

A rate limit component is used to limit the number of executions in a certain amount of time. It is configured by setting the time between two executions. For example, a time of 200 milliseconds yields a maximum frequency of 1/0.2 s = 5 Hz.

If the rate limit component is called the next time before the configured time has been elapsed, the component will wait.

You have to create a global element, where you define the minimum time between two calls. Several components can be linked to one global element. The components linked to the same global element share the rate limit.

If you want to create several "channels" which are limited (with the same or other parameters), you have to create several global elements.

Unbounded & Bounded Buffer

If a flow is executed in parallel and the rate limit processor uses the unbounded buffer it can happen that the memory overflows. To prevent this the rate limit processor can use a bounded buffer with a maximum size. If this size is exceeded, an exception of type Buffer.OVERFLOW is thrown and the unbounded event can be handled in order to give the consumer a quick response.

Fixed delay

The fixed delay component is used to delay a flow for a certain amount of time. It does not need a global configuration, just configure the time in the component. It can be used to simulate (mock) another element in benchmark scenarios.

Handle 429

A scope in which you can place an HTTP request to a rate limited resource. When the resource follows the HTTP RFC, it will answer with status code 429 and a header "retry-after" with a wait time in seconds (or a time when you are allowed to make the next request). The scope evaluates both values. When the wait response code is returned, it will wait up to the specified point in time and try again. This wait is associated with an ID: Other occurrences of this scope in the same application with the same ID will not start the first call, but "join" the waiting room to the point in time. For these "joins", you can specify an additional wait time. This avoids all waiting operations fire up at exactly the same time, overloading your own application and the target server.

The times returned by the DataWeave expressions are all in milliseconds. The default values are:

Note: The default of the HTTP requestor is to throw an error when the server returns a 429 status code, so you have to configure a response validator to accept 429.

Note for testing: The scope evaluates the expressions attributes.statusCode and attributes.headers. In case the attributes are missing completely (e.g. in an MUnit test), the scopes handles it as success. When you inject your own attributes (e.g. in a Mock), make sure to use mime type application/java. In case you don't inject attributes, be careful that they are really empty, and you don't have some stray attributes from previous message processors or the source in you event.

Here a complete example:

<rate-limiter:handle-429
    id="ping-resource" numberOfRetries="5" waitStatusCode="429" 
    waitTimeExpression='#[(headers."retry-after" default "0" as Number) * 1000]' 
    joinWaitTimeExpression="#[1000]">
    <http:request method="GET" doc:name="/ping" config-ref="ping-config" path="/ping" >
        <http:response-validator >
            <http:success-status-code-validator values="100..399,429" />
        </http:response-validator>
    </http:request>
</rate-limiter:handle-429>

Maven dependency

Add this dependency to your application pom.xml

<dependency>
    <groupId>de.codecentric.mule.modules</groupId>
    <artifactId>rate-limiter</artifactId>
    <version>1.2.1</version>
    <classifier>mule-plugin</classifier>
</dependency>

Release notes

Hint for developers

Must be compiled with a JDK 1.8, otherwise tests will not run (missing package in newer JDKs). This is a restriction of the Mule SDK.

You can use the JDK bundled with AnypointStudio, e.g. in: C:/AnypointStudio-7.15.0/plugins/org.mule.tooling.jdk.v8.win32.x86_64_1.1.1