{"id":15132505,"url":"https://github.com/arpan491/api-ratelimiter","last_synced_at":"2026-02-25T16:32:32.290Z","repository":{"id":257261874,"uuid":"857759850","full_name":"arpan491/API-RateLimiter","owner":"arpan491","description":"A Go-based distributed rate-limiting library using Redis, supporting Token Bucket, Leaky Bucket, Sliding Window, and Counter algorithms. It's lightweight, scalable, and thread-safe, ideal for API throttling with minimal overhead.","archived":false,"fork":false,"pushed_at":"2024-09-15T18:48:17.000Z","size":390,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-06T15:53:42.242Z","etag":null,"topics":["concurrency","counter-algorithm","go","leaky-bucket","redis","sliding-window","thread-safe","token-bucket"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arpan491.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-15T14:41:33.000Z","updated_at":"2024-11-21T09:32:06.000Z","dependencies_parsed_at":"2025-02-08T12:43:07.529Z","dependency_job_id":null,"html_url":"https://github.com/arpan491/API-RateLimiter","commit_stats":null,"previous_names":["arpan491/api-ratelimiter"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/arpan491/API-RateLimiter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arpan491%2FAPI-RateLimiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arpan491%2FAPI-RateLimiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arpan491%2FAPI-RateLimiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arpan491%2FAPI-RateLimiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arpan491","download_url":"https://codeload.github.com/arpan491/API-RateLimiter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arpan491%2FAPI-RateLimiter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279164304,"owners_count":26117662,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-16T02:00:06.019Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["concurrency","counter-algorithm","go","leaky-bucket","redis","sliding-window","thread-safe","token-bucket"],"created_at":"2024-09-26T04:20:20.813Z","updated_at":"2025-10-16T07:05:09.706Z","avatar_url":"https://github.com/arpan491.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Distributed Rate-Limiting Library Using Redis\r\n\r\n### Overview\r\nThis library is designed to implement distributed rate limiting in a simple, no-nonsense way. Similar to how an ID generator works, the client retrieves data from Redis in batches (essentially just values). As long as these values aren't consumed, the rate limit is not exceeded.\r\n\r\n### Key Advantages\r\n* Minimal dependencies—only Redis is required, no additional services\r\n* Utilizes Redis' internal clock, so clients don't need synchronized clocks\r\n* Thread- and coroutine-safe\r\n* Low overhead on the system and minimal pressure on Redis\r\n\r\n### Important Notes\r\nDifferent limiter types use different Redis key data structures, so they cannot share the same Redis key name.\r\n\r\nExample:\r\n```\r\n127.0.0.1:6379\u003e type key:leaky\r\nstring\r\n127.0.0.1:6379\u003e type key:token\r\nhash\r\n127.0.0.1:6379\u003e hgetall key:token\r\n\"token_count\"\r\n\"0\"\r\n\"updateTime\"\r\n\"1613805726567122\"\r\n127.0.0.1:6379\u003e get key:leaky\r\n\"1613807035353864\"\r\n```\r\n\r\n### Installation\r\n```\r\ngo get github.com/arpan491/API-RateLimiter\r\n```\r\n\r\n### Usage\r\n\r\n#### 1. Create a Redis client\r\nUsing the `\"github.com/go-redis/redis\"` package, the library supports both master-slave and cluster Redis modes.\r\n```\r\nclient := redis.NewClient(\u0026redis.Options{\r\n    Addr:     \"localhost:6379\",\r\n    Password: \"xxx\", // no password\r\n    DB:       0,     // default DB\r\n})\r\n```\r\nOr, for Redis cluster mode:\r\n```\r\nclient := redis.NewClusterClient(\u0026redis.ClusterOptions{\r\n    Addrs:    []string{\"127.0.0.1:6379\"},\r\n    Password: \"xxxx\",\r\n})\r\n```\r\n\r\n#### 2. Create a RateLimiter\r\n\r\nFor a token bucket rate limiter that allows 200 operations per second:\r\n```\r\nlimiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, \"push\", time.Second, 200, 20, 5)\r\n```\r\nFor 200 operations per minute:\r\n```\r\nlimiter, err := ratelimit.NewTokenBucketRateLimiter(ctx, client, \"push\", time.Minute, 200, 20, 5)\r\n```\r\n\r\n#### 2.1 Counter Algorithm\r\n```\r\nfunc NewCounterRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,\r\n    throughput int, batchSize int) (Limiter, error)\r\n```\r\n\r\n| Parameter  | Description                                                                 |\r\n|------------|-----------------------------------------------------------------------------|\r\n| `key`      | Redis key name                                                              |\r\n| `duration` | Time interval for the allowed operation throughput                           |\r\n| `throughput` | Allowed number of operations within the given time interval                 |\r\n| `batchSize` | Number of operations retrieved from Redis in one batch                      |\r\n\r\n#### 2.2 Token Bucket Algorithm\r\n```\r\nfunc NewTokenBucketRateLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,\r\n    throughput int, maxCapacity int, batchSize int) (Limiter, error)\r\n```\r\n\r\n| Parameter    | Description                                                                 |\r\n|--------------|-----------------------------------------------------------------------------|\r\n| `key`        | Redis key name                                                              |\r\n| `duration`   | Time interval for the allowed operation throughput                          |\r\n| `throughput` | Number of operations allowed within the given time interval                 |\r\n| `maxCapacity`| Maximum tokens that can be stored in the token bucket                        |\r\n| `batchSize`  | Number of operations retrieved from Redis in one batch                      |\r\n\r\n#### 2.3 Leaky Bucket Algorithm\r\n```\r\nfunc NewLeakyBucketLimiter(ctx context.Context, client redis.Cmdable, key string, duration time.Duration,\r\n    throughput int) (Limiter, error)\r\n```\r\n\r\n| Parameter    | Description                                                                 |\r\n|--------------|-----------------------------------------------------------------------------|\r\n| `key`        | Redis key name                                                              |\r\n| `duration`   | Time interval for the allowed operation throughput                          |\r\n| `throughput` | Number of operations allowed within the given time interval                 |\r\n\r\n#### 2.4 Sliding Time Window\r\n```\r\nNewSlideTimeWindowLimiter(throughput int, duration time.Duration, windowBuckets int) (Limiter, error)\r\n```\r\n\r\n| Parameter       | Description                                                                 |\r\n|-----------------|-----------------------------------------------------------------------------|\r\n| `duration`      | Time interval for the allowed operation throughput                          |\r\n| `throughput`    | Number of operations allowed within the given time interval                 |\r\n| `windowBuckets` | Number of buckets representing a segment of the time window (`duration/windowBuckets`) |\r\n\r\nNote: The sliding window limiter operates in-memory and doesn't use Redis, making it unsuitable for distributed rate-limiting scenarios.\r\n\r\n### Example\r\n[More examples](https://github.com/arpan491/API-RateLimiter/tree/main/example)\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"github.com/go-redis/redis/v8\"\r\n    \"github.com/arpan491/API-RateLimiter\"\r\n    slog \"github.com/vearne/simplelog\"\r\n    \"sync\"\r\n    \"time\"\r\n)\r\n\r\nfunc consume(r ratelimit.Limiter, group *sync.WaitGroup, c *ratelimit.Counter, targetCount int) {\r\n    defer group.Done()\r\n    var ok bool\r\n    for {\r\n        ok = true\r\n        err := r.Wait(context.Background())\r\n        slog.Debug(\"r.Wait:%v\", err)\r\n        if err != nil {\r\n            ok = false\r\n            slog.Error(\"error:%v\", err)\r\n        }\r\n        if ok {\r\n            value := c.Incr()\r\n            slog.Debug(\"---value--:%v\", value)\r\n            if value \u003e= targetCount {\r\n                break\r\n            }\r\n        }\r\n    }\r\n}\r\n\r\nfunc main() {\r\n    client := redis.NewClient(\u0026redis.Options{\r\n        Addr:     \"localhost:6379\",\r\n        Password: \"xxeQl*@nFE\", // password\r\n        DB:       0,            // use default DB\r\n    })\r\n\r\n    limiter, err := ratelimit.NewTokenBucketRateLimiter(\r\n        context.Background(),\r\n        client,\r\n        \"key:token\",\r\n        time.Second,\r\n        10,\r\n        5,\r\n        2,\r\n    )\r\n\r\n    if err != nil {\r\n        fmt.Println(\"error\", err)\r\n        return\r\n    }\r\n\r\n    var wg sync.WaitGroup\r\n    total := 50\r\n    counter := ratelimit.NewCounter()\r\n    start := time.Now()\r\n    for i := 0; i \u003c 10; i++ {\r\n        wg.Add(1)\r\n        go consume(limiter, \u0026wg, counter, total)\r\n    }\r\n    wg.Wait()\r\n    cost := time.Since(start)\r\n    fmt.Println(\"cost\", cost, \"rate\", float64(total)/cost.Seconds())\r\n}\r\n```\r\n\r\n### Dependency\r\n[go-redis/redis](https://github.com/go-redis/redis)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farpan491%2Fapi-ratelimiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farpan491%2Fapi-ratelimiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farpan491%2Fapi-ratelimiter/lists"}