Recently, I had to limit request count for our API in Spring application.
I tried to write my own throttling implementation.
In first step, we need to define an annotation, which will help us to mark methods which calls should be throttled:
This annotation allow us to limit calls count in given time frame. If second is to big time frame, you can change it to millis or nanos.
Next step is implement a throttle manager:
All magic is placed in ThrottlingManager.
It takes endpoint method, userId and throttling config and it counts calls in given timeframe using Guava cache. Guava gives us simple tool to delete expired entries in our cache counter. Every endpoint call is represented in cache as a random number. We are not interested about request body, parameters etc. We only care about calls count.
Here is an implementation of simple ThrottlingConfig.
This is how our EnpointMethod looks like.
As we can see, it contains class and method name. We use objects of this class as ConcurrentHashMap key, remember to override hashCode and equals methods from Java Object class.
When we have these elements, we can implement aspect which will allow us to process throttling.
This aspect processes around method annotated with @Controller or @RestController. It constructs EndpointMethod object and checks, if method was annotated with @Throttling and build proper config, otherwise it takes default value. You can change this behaviour as you want.
It’s time to test our implementation. Let’s create simple endpoint:
This controller has throttled method, so if our throttling is working third call should be rejected with exception.
Let’s start our application with command: mvn spring-boot:run
and then type in our browser:
http://localhost:8080/test
Refresh page 2 times.
Now it’s time to check logs:
As we can see method was called 2 times but third call was rejected. You can see something familiar in your browser:
Mon Feb 17 08:57:02 CET 2020
There was an unexpected error (type=Too Many Requests, status=429).
User: test@domain.com, reached calls limit for method: io.okraskat.throttling.EndpointMethod@71fd5723
Hope this example will help you to deal with throttling or be an inspiration, how can you combine Spring and Guava features.
You can find the source code in my Github repository how-to under a throttling directory.
Hope you enjoy this post. If You have any questions or problems leave a comment or send email.