Skip to content

Conversation

mdemblani
Copy link

@mdemblani mdemblani commented Sep 19, 2025

Currently the RateLimitException raises an empty exception. The PR aims to modify the exception to add extra values which can then by the SDK/lib consumers to retreive more information from the given exception and also open up room for better handling of exceptions from Annotation @RateLimiting

Exception handling improvements:

  • Added new fields (retryAfterNanoSeconds, remainingTokens, and configurationName) and corresponding constructor/getters to the RateLimitException class to provide more context when a rate limit is exceeded.
  • Modified the rate limit check logic in RateLimitAspect to capture and log the retry time (retryAfterNanoSeconds) when a limit is hit, and to pass this value along with remaining tokens to the result object.

@mdemblani mdemblani marked this pull request as ready for review September 19, 2025 20:08
private final String configurationName;

public RateLimitException(Long retryAfterNanoSeconds, Long remainingTokens, String configurationName) {
super("Rate limit exceeded for configuration: " + configurationName + ". Retry after: " + (retryAfterNanoSeconds != null ? retryAfterNanoSeconds : 0) + "ns. Remaining tokens: " + (remainingTokens != null ? remainingTokens : 0));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure about it but can the remainingTokens be greater than 0?
Nanoseconds are hard to read. What about milliseconds? Or seconds?

The message line is a little bit to long. my suggestion:

super("Rate limit exceeded for configuration: " + configurationName + ". " +
                "Retry after: " + toMilliseconds(retryAfterNanoSeconds) + "ns. " +
                "Remaining tokens: " + toMilliseconds(remainingTokens));
// the slower variant
super("Rate limit exceeded for configuration %s : . Retry after: %sms . Remaining tokens: %s".formatted(
                configurationName,
                toMilliseconds(retryAfterNanoSeconds),
                toMilliseconds(remainingTokens))
        );
private static long toMilliseconds(Long retryAfterNanoSeconds) {
        return retryAfterNanoSeconds != null ? TimeUnit.NANOSECONDS.toMillis(retryAfterNanoSeconds) : 0;
    }

* This exception is thrown when the rate limit is reached in the context of a method level when using the
* {@link RateLimiting} annotation.
*/
public class RateLimitException extends RuntimeException {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Lomboks @Getter

RateLimitException ex1 = assertThrows(RateLimitException.class, () -> testService.withCacheKey("key1"));
assertTrue(ex1.getRetryAfterNanoSeconds() >= 0);
assertTrue(ex1.getRemainingTokens() >= 0);
assertNotNull(ex1.getConfigurationName());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertEquals("default", ex1.getConfigurationName());

private final long remainingTokens;
private final String configurationName;

public RateLimitException(Long retryAfterNanoSeconds, Long remainingTokens, String configurationName) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the cacheKey also of interest?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants