◉ Pulse
onizukaTP avatar
#30 today

onizukaTP/limitly

Java Framework #java #java21 #lua #micrometer

Production-grade Redis-backed rate limiter Spring Boot starter. Features atomic Lua execution, Token Bucket & Sliding Window algorithms, SpEL resolution, and Micrometer metrics.

Created Jul 29, 2026
Stars
7
Today
+7
Forks
0
Quality
95/100
Momentum
20

README

Fetched from GitHub on Oct 30, 2026, 10:17 PM UTC · README.md

View original on GitHub

Third-party content — Open Source Pulse is not the owner of this repository.

This README belongs to onizukaTP/limitly and its contributors. We fetch it directly from the project’s public GitHub repository and display it for reference only. All text, code, images and trademarks remain the property of their respective authors. See the repository for its license terms. Copyright / takedown policy.

Limitly — Redis-Backed Rate Limiter Spring Boot Starter

Java Version Spring Boot License

Limitly is a production-grade, zero-config, annotation-based rate limiting library built for Spring Boot applications powered by Redis. Built with Java 21, Spring Boot 3, and Lua Scripting to ensure race-condition-free, atomic operations across distributed pod replicas.


⚡ Features

  • Annotation-based DX: Drop @RateLimit on any @RestController endpoint.
  • Atomic Redis Execution: Zero race conditions under high concurrent traffic using Redis Lua scripts (EVALSHA/EVAL).
  • Dual Algorithms Supported:
    • Token Bucket: Smoothed traffic flow, configurable refill rates, low Redis memory footprint.
    • Sliding Window Log: Exact request-count precision using Redis Sorted Sets (ZSET).
  • Flexible Key Resolution:
    • USER: Resolves user Principal or X-User-ID header.
    • IP: Resolves real client IP (aware of X-Forwarded-For proxy headers).
    • SPEL: Dynamic SpEL expression support (e.g. #request.remoteAddr, #user.id).
  • Resilient Fallback Modes:
    • FAIL_OPEN: (Default) Allows request traffic through when Redis is unreachable.
    • FAIL_CLOSED: Throttles requests securely during Redis outages.
  • Production Observability: Built-in Micrometer metrics (ratelimiter.requests.allowed, ratelimiter.requests.denied, ratelimiter.redis.latency, ratelimiter.redis.failures) ready for Prometheus and Grafana dashboards.
  • RFC-compliant HTTP Headers: Automatically appends X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After HTTP headers on throttled 429 responses.

🏗️ High-Level Architecture

┌───────────────────────────────────────────────────────────┐
│                     Client Request                        │
└────────────────────────┬──────────────────────────────────┘
                         ▼
              ┌─────────────────────┐
              │ RateLimitInterceptor│  (HandlerInterceptor)
              └──────────┬──────────┘
                         │ resolves key via KeyResolver
                         ▼
              ┌─────────────────────┐
              │  RateLimiterService │
              └──────────┬──────────┘
                         │ executes Lua script atomically
                         ▼
              ┌─────────────────────┐
              │   Redis (Lua exec)  │
              └──────────┬──────────┘
                         │ Returns allowed/remaining/retryAfter
                         ▼
             ┌───────────────────────────┐
             │ Allowed: Continue (200)   │
             │ Denied: Return 429 + Retry│
             └───────────────────────────┘

🚀 Quick Start

1. Add Dependency

Add the starter dependency to your pom.xml:

<dependency>
    <groupId>io.github.tharunprabu</groupId>
    <artifactId>redis-rate-limiter-spring-boot-starter</artifactId>
    <version>0.1.0-SNAPSHOT</version>
</dependency>

2. Configure application.yml

spring:
  data:
    redis:
      host: localhost
      port: 6379

rate-limiter:
  enabled: true
  default-strategy: SLIDING_WINDOW
  default-key-resolver: USER
  fallback-mode: FAIL_OPEN
  redis:
    key-prefix: "ratelimit:"
  response:
    status: 429
    body: '{"error": "rate_limit_exceeded", "message": "Too many requests. Please try again later."}'
    include-retry-after-header: true
  metrics:
    enabled: true

3. Annotate Endpoints

@RestController
@RequestMapping("/api")
public class ProductController {

    // 5 requests per 10 seconds using Sliding Window Log
    @GetMapping("/products/search")
    @RateLimit(limit = 5, window = "10s", strategy = Algorithm.SLIDING_WINDOW)
    public ResponseEntity<?> search(@RequestParam String query) {
        return ResponseEntity.ok(Map.of("query", query));
    }

    // 10 requests per 1 minute based on IP address using Token Bucket algorithm
    @PostMapping("/ads")
    @RateLimit(key = "#request.remoteAddr", limit = 10, window = "1m", strategy = Algorithm.TOKEN_BUCKET)
    public ResponseEntity<?> createAd(HttpServletRequest request) {
        return ResponseEntity.ok("Ad created");
    }

    // Fail closed on critical resource if Redis connection drops
    @GetMapping("/critical")
    @RateLimit(limit = 2, window = "5s", onRedisFailure = FallbackMode.FAIL_CLOSED)
    public ResponseEntity<?> criticalEndpoint() {
        return ResponseEntity.ok("Access granted");
    }
}

📊 Comparison: Token Bucket vs Sliding Window Log

Feature Token Bucket Sliding Window Log
Data Structure Redis Hash (HMSET) Redis Sorted Set (ZSET)
Memory Footprint Extremely low (~2 fields per key) Proportional to request volume in window
Accuracy Continuous refill rate, allows micro-bursts 100% exact request count precision
Best Used For General API endpoints, bulk processing Strict financial APIs, authentication/login attempts

📈 Observability & Micrometer Metrics

When Micrometer and Spring Actuator are present, Limitly automatically records the following metrics:

  • ratelimiter.requests.allowed (Counter, tagged with key, route)
  • ratelimiter.requests.denied (Counter, tagged with key, route)
  • ratelimiter.redis.latency (Timer measuring Redis Lua script execution duration)
  • ratelimiter.redis.failures (Counter measuring Redis downtime fallback events)

🛠️ Project Structure

limitly/
├── redis-rate-limiter-core/                   # Core engine & Lua scripts (Zero Spring dependencies)
├── redis-rate-limiter-spring-boot-starter/    # Auto-Configuration, Interceptors, SpEL, Metrics
└── redis-rate-limiter-samples/demo-app/       # Executable Spring Boot sample application

📜 License

Distributed under the Apache 2.0 License. Built by Tharun prabu.

Rendered by GitHub from the repository’s README. Scroll to read the full file.
First trending

Jul 29, 2026

first spotted on the list

Best rank

#25

highest position reached

Appearances

2

times on the trending list

Quality score

95

out of 100

Momentum

20

trend strength indicator

Star velocity

0.08

stars per day since creation

Activity — last 60 days

daily counts, collected every 6 hours
  • Stars
  • Forks
  • Merged PRs
  • Issues
  • Closed issues

Collecting activity data since launch — check back in a few days.

Star history

total stars per snapshot
678onizukaTP/limitly · Jul 29, 2 PM UTC: 7 starsonizukaTP/limitly · Jul 30, 2 AM UTC: 7 stars2 PM8 PM2 AM

Rank history

position on trending · lower is better
#1#25#26#27#28#29#30Jul 29, 2 PM UTC: rank #25Jul 30, 2 AM UTC: rank #302 PM8 PM2 AM

3D card for your website

Live HTML card with a glass surface and pointer tilt. Paste the iframe on any website.

<iframe src="https://www.notionpulse.cc/embed/onizukaTP/limitly" width="420" height="240" style="border:0;max-width:100%;background:transparent" loading="lazy" title="onizukaTP/limitly — trending on Open Source Pulse"></iframe>

Stars badge

Show current stars in your README or profile. Auto-updates every 6 hours.

onizukaTP/limitly stars badge
Markdown
[![onizukaTP/limitly](https://www.notionpulse.cc/api/badge/onizukaTP/limitly.svg)](https://www.notionpulse.cc/repo/onizukaTP/limitly)
HTML
<a href="https://www.notionpulse.cc/repo/onizukaTP/limitly"><img src="https://www.notionpulse.cc/api/badge/onizukaTP/limitly.svg" alt="onizukaTP/limitly stars badge" /></a>

Repository of the Day

#25 Repository of the Day

Repository of the Week

#25 Repository of the Week

Repository of the Month

#25 Repository of the Month