{"id":25328663,"url":"https://github.com/kit/excess_flow","last_synced_at":"2025-10-29T04:32:30.484Z","repository":{"id":56845147,"uuid":"212869173","full_name":"Kit/excess_flow","owner":"Kit","description":"High precision redis based rate limiter","archived":false,"fork":false,"pushed_at":"2020-08-31T14:15:10.000Z","size":34,"stargazers_count":21,"open_issues_count":3,"forks_count":2,"subscribers_count":24,"default_branch":"master","last_synced_at":"2025-02-12T14:59:37.527Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-04T17:30:45.000Z","updated_at":"2024-05-02T20:18:51.000Z","dependencies_parsed_at":"2022-09-09T21:10:57.642Z","dependency_job_id":null,"html_url":"https://github.com/Kit/excess_flow","commit_stats":null,"previous_names":["kit/excess_flow"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fexcess_flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fexcess_flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fexcess_flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kit%2Fexcess_flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kit","download_url":"https://codeload.github.com/Kit/excess_flow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238772126,"owners_count":19527879,"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":"2025-02-14T02:56:33.107Z","updated_at":"2025-10-29T04:32:30.187Z","avatar_url":"https://github.com/Kit.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ExcessFlow [![Build Status][ci-image]][ci] [![Code Climate][codeclimate-image]][codeclimate] [![Gem Version][version-image]][version]\nExcessFlow is a high precision Redis based rate limiter; it means that even with\nhundreds and even thousands requests coming in all at once it will not allow an\noccasional request slip over limit (causing potential race conditions or\nunwanted extra invocations of your code).\n\nCan be used with any Ruby or Ruby on Rails project. Can be used in any\ndistributed environment without any additional setup.\n\n## How it works\nOnce a request comes in ExcessFlow will setup a global mutex using Redis. Once\nmutex is set up it will sort out your request's limits and see if it can be\nfulfilled or you are over your quota. In either case mutex will be released and\nExcessFlow will continue either with execution of your code or return an\n`ExcessFlow::FailedExecution` as a result.\n\nThis global mutex ensures that only one check for a limit can be active at a\ntime thus eliminating race conditions.\n\n# Installation\nAdd the following line to your Gemfile:\n\n```\ngem 'excess_flow'\n```\nAnd run `bundle` from your shell.\n\nTo install gem manually run from your shell:\n\n```\ngem install excess_flow\n```\n\n## Requirements\nOnly requirement to run this gem is [Redis](https://redis.io/). Other than that\nit is not dependant on any other framework or system.\n\n## Configration\nThe only thing you need to set up is URL of your Redis server. You can do this\nby either setting `EXCESS_FLOW_REDIS_URL` environment variable or by executing\nfollowing code during runtime. For Ruby on Rails create\n`config/initializers/excess_flow.rb` file and put the following code in there:\n\n```\nExcessFlow.configure do |configuration|\n  configuration.redis_url = \u003cREDIS_URL\u003e\nend\n```\n\nThere are two ways to configure ExcessFlow: using environment variables or\ninvoking configuration block during runtime.\n\nFollowing settings are supported:\n\n| Variable | Method | Settings |\n| ------------- | ------------- | ------------- |\n| `EXCESS_FLOW_CONNECTION_POOL` | `connection_pool` | Redis connection pool size to share amongst the fibers or threads in your Ruby. Defaults to `100`. |\n| `EXCESS_FLOW_CONNECTION_TIMEOUT` | `connection_timeout`  | How long to wait for a connection from connection pool to become available (in seconds). Defaults to `3`. |\n| `EXCESS_FLOW_REDIS_URL` | `redis_url` | URL of your Redis server that will be used for caching. Defaults to `redis://localhost:6379/1`. |\n| `EXCESS_FLOW_REDIS_SENTINELS` | `sentinels` | (optional) Comma separated list of Sentinels IPs for Redis. Defaults to `nil`. Example value: `8.8.8.8:42,8.8.4.4:42`. |\n\n## Usage\nTo rate limit your request simply wrap your code into `throttle` block:\n\n```\nExcessFlow.throttle(key: 'meaning_of_life', limit: 42, ttl: 42) do\n  21 + 21\nend\n```\n\nThis returns a `ExcessFlow::RateLimitedExecutionResult` class that wraps result\nof execution of your code. If you need to know if request was within limit call\n`success?` method on it. If you need to get access to result call `result`\nmethod.\n\n```\nexecution = ExcessFlow.throttle(key: 'meaning_of_life', limit: 42, ttl: 42) do\n  21 + 21\nend\n=\u003e #\u003cExcessFlow::RateLimitedExecutionResult:0x00005588c4c084e0 @result=\"42\"\u003e\n\nexecution.success?\n=\u003e true\n\nexecution.result\n=\u003e 42\n```\n\nIf execution of your code was rate limited then `ExcessFlow::RateLimitedExecutionResult`\nwill hold `ExcessFlow::FailedExecution` as a result and `success?` method will\nreturn false.\n\n```\nexecution = ExcessFlow.throttle(key: 'meaning_of_life', limit: 0, ttl: 42) do\n  21 + 21\nend\n=\u003e #\u003cExcessFlow::RateLimitedExecutionResult:0x00005588c4c084e0\n@result=\"#\u003cExcessFlow::FailedExecution:0x00005588c4c30350\u003e\"\u003e\n\nexecution.success?\n=\u003e false\n\nexecution.result\n=\u003e #\u003cExcessFlow::FailedExecution:0x00005588c4c30350\u003e\n\n```\n\n`throttle` method accepts 4 named arguments:\n\n| Argument | Meaning |\n| ------------- | ------------- |\n| `key` | Name of window in which to keep requests that should be limited. |\n| `ttl` | Time in seconds for which to keep a window open. |\n| `limit` | Number of requests allowed to be done within single unique window. |\n| `strategy` | (optional) Rate limiting strategy to use. Defaults to `:fixed_window`. Available options are `:fixed_window` and `:sliding_window`. |\n\n### Rate limiting strategies\nCurrently there are two strategies available: `:fixed_window` and\n`:sliding_window`. If in doubt and don't know which one to use start with\n`:fixed_window` as it is more lightweight and will guarantee you better\nperformance.\n\n#### :fixed_window\nFixed window strategy allows you to make N requests in a O period of time. After\nO time passes counter is re-set allowing you to make another N requests.\n\nThink about a bucket that you can fill with pebbles. Once full you can no longer\nadd pebbles to it and has to wait for someone to come and empty it for you so\nyou can start filling it with pebbles again. Catch is that that someone comes\nevery O minutes to empty it.\n\n#### :sliding_window\nSliding window strategy allows you to make N requests in a O period of time\nwhere O is tracked for each request individually.\n\nThink about bucket with pebbles again. This time someone is sitting right next\nto you as you fill it and tracks time at which you put each individual pebble\nin. Once O minutes is passed they remove the pebble out of bucket.\n\n## Development\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run\n`rspec` to run the tests. You can also run `bin/console` for an interactive\nprompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To\nrelease a new version, update the version number in `version.rb`, and then run\n`bundle exec rake release`, which will create a git tag for the version, push\ngit commits and tags, and push the `.gem` file to\n[rubygems.org](https://rubygems.org).\n\n## Contributing\nBug reports and pull requests are welcome on GitHub at\nhttps://github.com/ConvertKit/excess_flow. This project is intended to be a\nsafe, welcoming space for collaboration, and contributors are expected to adhere\nto the [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\nThe gem is available as open source under the terms of the\n[Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).\n\n## Code of Conduct\nEveryone interacting in the ExcessFlow project’s codebases, issue\ntrackers, chat rooms and mailing lists is expected to follow the [code of\nconduct](https://github.com/ConvertKit/excess_flow/blob/master/CODE_OF_CONDUCT.md).\n\n[ci]: https://circleci.com/gh/ConvertKit/excess_flow\n[ci-image]: https://circleci.com/gh/ConvertKit/excess_flow.svg?style=svg\n[codeclimate]:\nhttps://codeclimate.com/github/ConvertKit/excess_flow/maintainability\n[codeclimate-image]:\nhttps://api.codeclimate.com/v1/badges/f9ca3b6dda3b492b125e/maintainability\n[version]: https://badge.fury.io/rb/excess_flow\n[version-image]: https://badge.fury.io/rb/excess_flow.svg\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkit%2Fexcess_flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkit%2Fexcess_flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkit%2Fexcess_flow/lists"}