{"id":28310316,"url":"https://github.com/nickgaya/redbucket","last_synced_at":"2026-05-15T13:31:37.394Z","repository":{"id":54291816,"uuid":"245967439","full_name":"nickgaya/redbucket","owner":"nickgaya","description":"Python rate limiting library using Redis for shared state.","archived":false,"fork":false,"pushed_at":"2023-07-20T15:09:46.000Z","size":42,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-28T12:00:44.284Z","etag":null,"topics":["python","rate-limits","redis"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"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/nickgaya.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","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":"2020-03-09T07:14:42.000Z","updated_at":"2022-10-31T04:50:35.000Z","dependencies_parsed_at":"2024-12-27T07:00:49.717Z","dependency_job_id":null,"html_url":"https://github.com/nickgaya/redbucket","commit_stats":{"total_commits":19,"total_committers":2,"mean_commits":9.5,"dds":"0.052631578947368474","last_synced_commit":"820adbf32f0a37bd73832a1a82195cd966a469e4"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/nickgaya/redbucket","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickgaya%2Fredbucket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickgaya%2Fredbucket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickgaya%2Fredbucket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickgaya%2Fredbucket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickgaya","download_url":"https://codeload.github.com/nickgaya/redbucket/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickgaya%2Fredbucket/sbom","scorecard":{"id":685082,"data":{"date":"2025-08-11","repo":{"name":"github.com/nickgaya/redbucket","commit":"820adbf32f0a37bd73832a1a82195cd966a469e4"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.5,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/19 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v0.1.0 not signed: https://api.github.com/repos/nickgaya/redbucket/releases/24336428","Warn: release artifact v0.1.0 does not have provenance: https://api.github.com/repos/nickgaya/redbucket/releases/24336428"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 3 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2023-120 / GHSA-45c4-8wx5-qw6w","Warn: Project is vulnerable to: PYSEC-2024-24 / GHSA-5h86-8mv2-jq9f","Warn: Project is vulnerable to: GHSA-5m98-qgg9-wh84","Warn: Project is vulnerable to: GHSA-7gpw-8wmc-pm8g","Warn: Project is vulnerable to: GHSA-8495-4g3g-x7pr","Warn: Project is vulnerable to: PYSEC-2024-26 / GHSA-8qpw-xqxj-h4r2","Warn: Project is vulnerable to: GHSA-9548-qrrj-x5pj","Warn: Project is vulnerable to: PYSEC-2023-246 / GHSA-gfw2-4jvh-wgfg","Warn: Project is vulnerable to: GHSA-pjjw-qhg8-p2p9","Warn: Project is vulnerable to: PYSEC-2023-250 / GHSA-q3qx-c6g2-7pw2","Warn: Project is vulnerable to: PYSEC-2023-251 / GHSA-qvrw-v9rv-5rjx","Warn: Project is vulnerable to: PYSEC-2023-247 / GHSA-xx9p-xxvh-7g8j"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T00:32:19.779Z","repository_id":54291816,"created_at":"2025-08-22T00:32:19.779Z","updated_at":"2025-08-22T00:32:19.779Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33068360,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T11:35:32.926Z","status":"ssl_error","status_checked_at":"2026-05-15T11:35:31.362Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["python","rate-limits","redis"],"created_at":"2025-05-24T11:10:58.050Z","updated_at":"2026-05-15T13:31:37.377Z","avatar_url":"https://github.com/nickgaya.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Red Bucket\n\nPython rate limiting library using Redis for shared state.\n\n## Installation\n\nTo install the latest released version:\n\n    pip install redbucket\n\nTo install the current development version from the master branch on GitHub:\n\n    pip install -U git+https://github.com/nickgaya/redbucket.git\n\n## Usage\n\nThe following snippet configures a rate limiter with two rate limiting zones:\n\n```python3\nfrom redbucket import RedisRateLimiter, RateLimit, Zone\nfrom redis import Redis\n\n\n# Accept up to 5 requests per user per second.\n# Allow bursts of up to 10 requests.\nuser_zone = Zone('user', rate=5)\nuser_limit = RateLimit(user_zone, burst=10)\n\n# Accept up to 20 requests per IP per second.\n# Allow up to 10 excess requests with a delay.\nip_zone = Zone('ip', rate=20)\nip_limit = RateLimit(ip_zone, delay=10)\n\nredis = Redis()\nrate_limiter = RedisRateLimiter(redis)\nrate_limiter.configure(user=user_limit, ip=ip_limit)\n```\n\nWe can now use the rate limiter as follows:\n\n```python3\ndef example_operation(user, ip_address):\n    response = rate_limiter.request(user=user, ip=ip_address)\n    if not response.accepted:\n        raise Exception(\"Rate limit exceeded\")  # Reject request\n    if response.delay \u003e 0:\n        sleep(response.delay)  # Wait for delay seconds\n    ...  # Perform operation\n```\n\nNote that we don't have to specify a key for every zone. For example, we could\nexclude certain IP addresses from IP rate limiting while still applying the\nuser rate limit, as follows:\n\n```python3\ndef example_operation(user, ip_address):\n    if is_whitelisted(ip_address):\n        response = rate_limiter.acquire(user=user)\n    else:\n        response = rate_limiter.acquire(user=user, ip=ip_address)\n    ...\n```\n\n### Implementations\n\nThe default `RedisRateLimiter` uses Redis's Lua script engine to atomically\nupdate rate limiter state. This implementation requires Redis 3.2 or greater.\nFor older Redis versions, you can use the `RedisTransactionalRateLimiter`.\n\nWhere supported, the script-based implementation is recommended as it handles\neach rate limiting request in a single round-trip to the Redis server, whereas\nthe transactional implementation performs several consecutive Redis commands\nper request.\n\n### State encoding\n\nBy default, rate limiter state is stored in Redis using a packed binary\nrepresentation. You can switch to JSON for a less efficient but more\nhuman-readable encoding.\n\n    rate_limiter = RedisRateLimiter(redis, codec='json')\n\n## Rate limiting model\n\nRed Bucket uses a rate limiting model inspired by [Nginx][rate-limiting-nginx].\nRate limiting state is stored in one or more **zones**. Each zone has a name\nand a base **rate**. A zone represents a namespace of rate limiting **keys**. A\n**rate limit** references a zone along with two parameters, **burst** and\n**delay**. A **rate limiter** references one or more rate limits.\n\nTo apply rate limiting to an operation, the application makes a **request** to\nthe rate limiter by specifying a key for each desired rate limit. The rate\nlimiter evaluates each rate limit to determine whether to reject, delay, or\nimmediately accept the request. If using multiple rate limits, the most\nrestrictive outcome will be applied.\n\nFor a rate limit with base rate \u003ci\u003er\u003c/i\u003e, burst value \u003ci\u003eb\u003c/i\u003e, and delay value\n\u003ci\u003ed\u003c/i\u003e, the rate limiter maintains a virtual counter for each key that\ncontinuously increases at a rate of \u003ci\u003er\u003c/i\u003e requests per second up to a\nmaximum value of\n\u003cspan style=\"white-space: nowrap;\"\u003e\u003ci\u003eb\u003c/i\u003e + 1\u003c/span\u003e. When a request arrives,\nthe rate limiter checks the current value of the counter \u003ci\u003ev\u003c/i\u003e. If\n\u003cspan style=\"white-space: nowrap;\"\u003e\u003ci\u003ev\u003c/i\u003e \u0026minus; 1 \u0026ge; 0\u003c/span\u003e, the rate\nlimiter decrements the counter by 1 and accepts the request immediately. If\n\u003cspan style=\"white-space: nowrap;\"\u003e\u003ci\u003ev\u003c/i\u003e \u0026minus; 1 \u0026ge; \u0026minus;\u003ci\u003ed\u003c/i\u003e\u003c/span\u003e,\nthe rate limiter decrements the counter by 1 and accepts the request after a\ndelay of\n\u003cspan style=\"white-space: nowrap;\"\u003e(\u003ci\u003ev\u003c/i\u003e \u0026minus; 1) / \u003ci\u003er\u003c/i\u003e\u003c/span\u003e\nseconds. Otherwise, *i.e.* if\n\u003cspan style=\"white-space: nowrap;\"\u003e\u003ci\u003ev\u003c/i\u003e \u0026minus; 1 \u0026lt; \u0026minus;\u003ci\u003ed\u003c/i\u003e\u003c/span\u003e,\nthe rate limiter rejects the request.\n\nIn practice, this means that from an initial idle state for a given key, the\nrate limiter will allow a burst of\n\u003cspan style=\"white-space: nowrap;\"\u003e\u003ci\u003eb\u003c/i\u003e + 1\u003c/span\u003e requests immediately,\nthrottle the next \u003ci\u003ed\u003c/i\u003e requests to the desired rate, and reject any further\nrequests past the limit.\n\n[rate-limiting-nginx]: https://www.nginx.com/blog/rate-limiting-nginx/ \"Rate Limiting with NGINX\"\n\n### Comparison with Nginx\n\nAs noted above, Red Bucket's rate limiting model is inspired by Nginx and\nuses a similar algorithm. However, the way burst and delay are specified is a\nlittle different. The following configuration examples illustrate the\ndifference.\n\n* Basic rate limiting\n\n    ```nginx\n    # nginx\n    limit_req zone=mylimit;\n    ```\n    ```python3\n    # redbucket\n    RateLimit(zone=mylimit)\n    ```\n\n* Burst with delay\n\n    ```nginx\n    # nginx\n    limit_req zone=mylimit burst=20;\n    ```\n    ```python3\n    # redbucket\n    RateLimit(zone=mylimit, delay=20)\n    ```\n\n* Burst with no delay\n\n    ```nginx\n    # nginx\n    limit_req zone=mylimit burst=20 nodelay;\n    ```\n    ```python3\n    # redbucket\n    RateLimit(zone=mylimit, burst=20)\n    ```\n\n* Two-stage rate limiting\n\n    ```nginx\n    # nginx\n    limit_req zone=ip burst=12 delay=8;\n    ```\n    ```python3\n    # redbucket\n    RateLimit(zone=mylimit, burst=8, delay=4)\n    ```\n\n## Development\n\nThis project uses Tox to manage virtual environments for unit tests and other\nchecks. Unit tests are written using the Pytest framework.\n\nThe unit tests require a Redis instance. By default, the tests attempt to\nconnect to port 6379 of localhost. This can be overridden by setting the\n`REDIS_URL` environment variable.\n\n    export REDIS_URL=redis://localhost:6379\n\nTo start a Redis Docker container for running the tests, you can use the\n*docker_redis.sh* script. For example, to run the tests against a Docker redis\ninstance, you can run:\n\n    ./docker_redis.sh tox\n\nYou can also run the script without a command and execute output to set\nenvironment variables in your current shell.\n\n    eval \"$(./docker_redis.sh)\"\n\nBy default, the script uses the `redis:alpine` image. You can supply a\ndifferent tag for the `redis` image with the `-t` flag, or a different image\nname with `-i`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickgaya%2Fredbucket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickgaya%2Fredbucket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickgaya%2Fredbucket/lists"}