{"id":21409848,"url":"https://github.com/stackbuilders/token-bucket","last_synced_at":"2025-07-23T21:12:27.920Z","repository":{"id":20473910,"uuid":"23751510","full_name":"stackbuilders/token-bucket","owner":"stackbuilders","description":"A TCP-based token bucket server written in Haskell","archived":false,"fork":false,"pushed_at":"2014-09-10T03:53:51.000Z","size":240,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-01-23T04:32:37.754Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","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/stackbuilders.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}},"created_at":"2014-09-07T03:23:00.000Z","updated_at":"2019-12-05T06:33:34.000Z","dependencies_parsed_at":"2022-07-31T21:18:01.266Z","dependency_job_id":null,"html_url":"https://github.com/stackbuilders/token-bucket","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/stackbuilders%2Ftoken-bucket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbuilders%2Ftoken-bucket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbuilders%2Ftoken-bucket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stackbuilders%2Ftoken-bucket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stackbuilders","download_url":"https://codeload.github.com/stackbuilders/token-bucket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243910690,"owners_count":20367538,"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-22T17:34:36.173Z","updated_at":"2025-03-16T17:45:08.125Z","avatar_url":"https://github.com/stackbuilders.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/stackbuilders/token-bucket.svg)](https://travis-ci.org/stackbuilders/token-bucket)\n\n# Token Bucket Server\n\nIn many applications you will want to throttle connections to an\nexternal integration. One common way to do so is with a\n[token bucket algorithm](http://en.wikipedia.org/wiki/Token_bucket).\n\nThis application is a TCP server which follows the token bucket\nalgorithm. By connecting to this server, clients can easily follow\nrate limiting rules according to a predefined acceptable number of\nqueries per second. A single server instance can be used for multiple\n\"buckets.\"\n\nThis library also includes a Haskell client that uses connection\npooling to connect to the token bucket server.\n\n# Required Resources\n\nWhen using a single server for multiple buckets, generally the server\nshould serve out tokens very close to the acceptable rate of queries\nper second. You should make sure that the server that you run the\ntoken bucket server on has a number of cores somewhere near the number\nof buckets that you define to ensure that it can keep up with\nrefilling the token buckets at the correct rate.\n\nIf you are running the token bucket server on the same machine that is\ndoing other processing work you should have a number of cores that\nallows for the processing work plus the token bucket server.\n\n# Benchmarks\n\nTesting shows that client applications should be held very near the\ndesired rate. However short samples could lead to results over the\ndesired rate, and when machines are overloaded the actual rate will\nlikely be lower than the specified queries per second.\n\nFrom a test script included with the application, the rate below was\nachieved when running the test application and the token bucket server\non the same machine:\n\n## Trial run with 2 threads doing 100000 requests each and a 0.001 sleep interval.\n\n|       name |       time |    granted |       rate |       goal |      dev % |\n|        --- |        --- |        --- |        --- |        --- |        --- |\n|    bucketa |     133.11 |        134 |       1.01 |          1 |       0.67 |\n|    bucketb |     131.45 |      13039 |      99.20 |        100 |      -0.80 |\n|    bucketc |     131.32 |      61836 |     470.88 |        500 |      -5.82 |\n\n### Benchmark Results Explained\n\nThe deviation for the 1 QPS bucket above is acceptable, since a token\nwas added to the bucket by the server in the last partial second of\nquerying.\n\nIt is likely that the test machine couldn't keep up with the demand at\nthe higher bucket levels, so we see deviation increasing as the QPS\nrate increases to 500 QPS. This may be mitigated by separating out the\nrequesting client from the server machine, or running on a machine\nwith more cores if this QPS level is needed.\n\n# Usage\n\n## Server Usage\n\nCreate a configuration file with each line containing a bucket name a\nspace, and then the number of operations per second that is acceptable\nfor each bucket. Buckets can be named using any non-space character.\n\n    bucket_a  1\n    bucket_b  100\n\nRun the server, specifying the port and path to the configuration file:\n\n    cabal run 4444 /path/to/config_filename\n\n## Haskell Client Usage\n\nOnce a server is started, you can connect to the server and request a\ntoken as follows (assuming the server is running on localhost port\n4444):\n\n```haskell\nλ: import qualified Network.TokenBucket.Client as C\nλ: pool \u003c- C.connect \"localhost\" 4444\nλ: C.get pool \"bucket_a\"\nλ: Right True\n```\n\n# Protocol\n\nClients should connect to the server using TCP. The server responds to\nthe commands `get bucket_name`, where `bucket_name` is the name of a\nbucket specified in the configuration, and `quit` which ends the TCP\nsession.\n\n## `get bucket_name`\n\nTries to get a token from the given `bucket_name`.\n\nThe value `bucket_name` should be one of the buckets in your configuration.\n\nThe `get bucket_name` command returns the following values:\n\n* `1` - A token was successfully obtained.\n* `0` - The given bucket currently has no tokens.\n* `BUCKET NOT FOUND` - the bucket name was not found in the\n  configuration.\n\n## `quit`\n\nEnds the current session. Returns `BYE`.\n\n# License\n\nMIT, see [the LICENSE file](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackbuilders%2Ftoken-bucket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstackbuilders%2Ftoken-bucket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstackbuilders%2Ftoken-bucket/lists"}