애플리케이션 디자인

Manage 429 RateLimit Errors with Spring WebClient

5 분 읽기

I have recently taken over the maintenance of a 스프링 부트 project. This project has some RateLimit errors in the logs when the app was contacting a remote REST API. Turns out that this app was also using the synchronous, blocking RestTemplate client to make the API calls, instead of the newer Spring WebClient, that happens to be using the Reactor API under the hood.

And you know what is great about Reactor and using Reactive APIs in general? It makes programming with Data Stream so easy. Which also means it makes retry strategies implementation easier.

Let’s talk about the error in the log first. What I got looked like this:

As usual, the interesting bit in stack traces is at the top. The error is 429 Too Many Requests, and the message says there is a 1 minute rate limit. Decomposing this, the HTTP status code returned is 429. It’s a Rate Limit error, meaning the API tells the caller it has sent too many request. This can usually be solved by waiting a bit, and you might even have a Retry-after header in the response telling you how long you have to wait.

Let’s see how we can get that information with Spring’s WebClient:

This code is sending a GET request. The WebClient allows us to take a look at the request’s response and react appropriately thanks to the onStatus method. The first parameter is a boolean used to filter on returned HTTP Status code. Here, when the status code is 429, we do something.

We take a look at the Response headers, look if there is a Retry-After header, if so, we initialize the delayInSeconds variable with it, if not, we set a 60 default value. Then we can send back the Response body mapped to a RateLimitException. The body content will be used as an error message and the delayInSeconds will be available in a separate field. Take a look at the Exception code for more details:

So what needs to be done is catching this specific error and then retrying after the given duration. Reactor makes that easy by providing Retries strategies. All you need to do is call the retryWhen method:

There are different Retry methods, here we can use the withThrowable() builder. It gives a Flux that should contain the RateLimitException. So we start by applying a filter to make sure of that. Then we map that exception to the actual Retry object. Here it’s the Retry.fixedDelay strategy, taking a maximum attempts and duration as parameters. The duration comes from the RateLimitException that was thrown earlier.

With that, each time a request returns a 429, the client will wait the appropriate time until it retries. And it was much easier to implement with Reactor than using try/catch with Spring’s RestTemplate. I know Reactive programming might be a little intimidating at first, but it’s a great way to manage data streams like HTTP requests and responses, or to manage connections to databases that support reactive programming, like 카우치베이스.

Want some more help and ideas?

이 기사 공유하기

작가

로랑은 파리에 사는 찌질한 매니아 기질이 있는 헤비메탈 마니아입니다. 그는 주로 자바(Java)로 코드를 작성하고 AsciiDoc으로 구조화된 텍스트를 작성하며, 데이터, 리액티브 프로그래밍 및 기타 유행어 같은 주제에 대해 자주 이야기합니다. 그는 또한 Clever Cloud와 Nuxeo의 전직 개발자 애드보케이트로 활동하며 해당 커뮤니티가 더 크고 강하게 성장하도록 시간과 전문 지식을 쏟아부었습니다. 현재는 카우치베이스(Couchbase)에서 개발자 관계(Developer Relations)를 총괄하고 있습니다.

댓글 남기기

카우치베이스 카펠라를 시작할 준비가 되셨나요?

개발 시작하기

NoSQL을 탐색하고, 리소스를 찾아보고, 튜토리얼을 시작하려면 개발자 포털을 확인하세요.

카펠라 프리 사용하기

단 몇 번의 클릭으로 카우치베이스(Couchbase)를 직접 체험해 보세요. Capella DBaaS는 시작하기 가장 쉽고 빠른 방법입니다.

연락해

Couchbase 제품군에 대해 더 알고 싶으신가요? 저희가 도와드리겠습니다.