crossoverJie/JCSprout · warning · RuntimeException

request has bean limit

Error message

request has bean limit

What it means

Thrown by the CommonAspect @Before advice when redisLimit.limit() returns false, meaning the rate-limit check denied the request. This is the intended rate-limiting behaviour (the typo 'bean' should read 'been'): the caller has exceeded the configured request rate within the time window, so the aspect aborts the method invocation with a RuntimeException. It surfaces as a 500 to the HTTP caller unless caught by a controller advice.

Source

Thrown at MD/distributed/Distributed-Limit.md:458

    private static Logger logger = LoggerFactory.getLogger(CommonAspect.class);

    @Autowired
    private RedisLimit redisLimit ;

    @Pointcut("@annotation(com.crossoverjie.distributed.annotation.CommonLimit)")
    private void check(){}

    @Before("check()")
    public void before(JoinPoint joinPoint) throws Exception {

        if (redisLimit == null) {
            throw new NullPointerException("redisLimit is null");
        }

        boolean limit = redisLimit.limit();
        if (!limit) {
            logger.warn("request has bean limit");
            throw new RuntimeException("request has bean limit") ;
        }

    }
}
```

很简单,也是在拦截过程中调用限流。

当然使用时也得扫描到该包:

```java
@ComponentScan(value = "com.crossoverjie.distributed.intercept")
```

### 总结

**限流**在一个高并发大流量的系统中是保护应用的一个利器,成熟的方案也很多,希望对刚了解这一块的朋友提供一些思路。

View on GitHub (pinned to fc4c6e5f6d)

Solutions

  1. Tune the rate-limit parameters (requests per window) in the @CommonLimit annotation or Redis config to match your traffic profile.
  2. Add a @ControllerAdvice / @ExceptionHandler that catches this RuntimeException and returns HTTP 429 (Too Many Requests) instead of a 500.
  3. Ensure the limit key correctly distinguishes clients (forward real IP from proxy headers) so one client does not exhaust the budget for all.
  4. If the limit is expected, handle it client-side with backoff and retry.

Example fix

// before — caller gets a raw 500
throw new RuntimeException("request has bean limit");

// after — return a proper 429
@ControllerAdvice
public class RateLimitHandler {
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<String> onRateLimit(RuntimeException e) {
        if (e.getMessage() != null && e.getMessage().contains("limit")) {
            return ResponseEntity.status(429).body("Rate limit exceeded");
        }
        throw e;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation can prevent this — it is the rate limit working as designed.
// Instead, track your request rate client-side and back off if approaching the limit.

Try / catch

// Server-side: convert the raw RuntimeException into a proper 429.
@ControllerAdvice
public class RateLimitExceptionHandler {
    @ExceptionHandler
    public ResponseEntity<String> handle(RuntimeException e) {
        if (e.getMessage() != null && e.getMessage().contains("limit")) {
            return ResponseEntity.status(429)
                .header("Retry-After", "1")
                .body("Rate limit exceeded, please retry later.");
        }
        throw e;
    }
}

Prevention

When it happens

Trigger: A client calls a @CommonLimit-annotated method more times than the configured Redis-based limit allows within the sliding/fixed window. Under load testing (e.g. JMeter) a large fraction of requests hit this path once the rate budget is exhausted.

Common situations: Rate limit threshold set too low for legitimate traffic. Burst traffic from a single client or a shared NAT egress IP. The limit key (typically IP-based) collides because all requests appear to come from the same source behind a proxy without X-Forwarded-For handling. Load testing without accounting for rate limits.

Related errors


AI-assisted analysis of crossoverJie/JCSprout@fc4c6e5f6d (2026-08-14). Data as JSON: /api/errors/7db6f4bcf0a97859. Report an issue: GitHub.