{"id":21672544,"url":"https://github.com/redis-developer/fixed-window-rate-limiter","last_synced_at":"2025-05-08T21:44:27.180Z","repository":{"id":104843379,"uuid":"401197720","full_name":"redis-developer/fixed-window-rate-limiter","owner":"redis-developer","description":"Redis Fixed Window Rate Limiter with Spring Boot","archived":false,"fork":false,"pushed_at":"2021-09-10T05:30:54.000Z","size":67,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-31T18:41:13.816Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redis-developer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-08-30T02:53:12.000Z","updated_at":"2024-06-03T01:46:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"49a1f8be-e770-4f62-9472-2326241724c0","html_url":"https://github.com/redis-developer/fixed-window-rate-limiter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Ffixed-window-rate-limiter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Ffixed-window-rate-limiter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Ffixed-window-rate-limiter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis-developer%2Ffixed-window-rate-limiter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redis-developer","download_url":"https://codeload.github.com/redis-developer/fixed-window-rate-limiter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253154134,"owners_count":21862462,"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","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":[],"created_at":"2024-11-25T13:29:59.186Z","updated_at":"2025-05-08T21:44:27.167Z","avatar_url":"https://github.com/redis-developer.png","language":"Java","readme":"# Redis Fixed Window Rate Limiter\n\nSpring Data Reactive Redis implementation of Redis [\"Basic Rate Limiting\"](https://redis.com/redis-best-practices/basic-rate-limiting/) Recipe which is a \"Fixed Window\" Rate Limiter (a single counter per unit of time)\n\n## Implementation Details\n\nThe \"Basic Rate Limiting\" recipe calls for the use of a [Redis Transaction](https://redis.io/topics/transactions) in which the commands are sent to the server, accumulated in serial way and executed sequentially without any possible interruption by a request from another client.\n\nBasically, we want the `INCR` and `EXPIRE` calls to update the requests-per-unit-of-time counter to happen atomically or not at all. A \"best possible\" method with a reactive API is using the `ReactiveRedisTemplate` `execute` method which takes a\n`ReactiveRedisCallback` guaranteing that at least the commands will run on the same Redis\nconnection, but this is by no means a real \"transaction\".\n\n```java\nprivate Mono\u003cServerResponse\u003e incrAndExpireKey(String key, ServerRequest request,\n    HandlerFunction\u003cServerResponse\u003e next) {\n  return redisTemplate.execute(new ReactiveRedisCallback\u003cList\u003cObject\u003e\u003e() {\n    @Override\n    public Publisher\u003cList\u003cObject\u003e\u003e doInRedis(ReactiveRedisConnection connection) throws DataAccessException {\n      ByteBuffer bbKey = ByteBuffer.wrap(key.getBytes());\n      return Mono.zip( //\n          connection.numberCommands().incr(bbKey), //\n          connection.keyCommands().expire(bbKey, Duration.ofSeconds(59L)) //\n      ).then(Mono.empty());\n    }\n  }).then(next.handle(request));\n}\n```\n\n# Command Line Testing\n\nA simple way to test an API rate limiter is using [curl](https://curl.se) in a loop,\nsince we are testing a set number of requests per unit of time the curl loop below will\nsuffice:\n\n```\nfor n in {1..22}; do echo $(curl -s -w \" :: HTTP %{http_code}, %{size_download} bytes, %{time_total} s\" -X GET http://localhost:8080/api/ping); sleep 0.5; done\n```\n\nWe loop 22 times, the example code is set to 20 so 22 will allow us to see two 429 responses. The\ncurl flags used are as follows; first is -s that silences curl (makes it hide progress bar and errors), -w is the write out options in which we can pass a string with interpolated variables.\nThen we sleep 1/2 second between cycles.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Ffixed-window-rate-limiter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredis-developer%2Ffixed-window-rate-limiter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis-developer%2Ffixed-window-rate-limiter/lists"}