{"id":13409699,"url":"https://github.com/bandwidth-throttle/token-bucket","last_synced_at":"2026-01-11T16:52:53.434Z","repository":{"id":33978780,"uuid":"37725198","full_name":"bandwidth-throttle/token-bucket","owner":"bandwidth-throttle","description":"Implementation of the Token Bucket algorithm in PHP.","archived":false,"fork":false,"pushed_at":"2023-01-27T15:17:06.000Z","size":445,"stargazers_count":504,"open_issues_count":14,"forks_count":78,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-09-07T16:38:31.027Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bandwidth-throttle.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":"2015-06-19T14:07:28.000Z","updated_at":"2024-09-04T21:47:59.000Z","dependencies_parsed_at":"2023-02-15T10:31:14.543Z","dependency_job_id":null,"html_url":"https://github.com/bandwidth-throttle/token-bucket","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bandwidth-throttle%2Ftoken-bucket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bandwidth-throttle%2Ftoken-bucket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bandwidth-throttle%2Ftoken-bucket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bandwidth-throttle%2Ftoken-bucket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bandwidth-throttle","download_url":"https://codeload.github.com/bandwidth-throttle/token-bucket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240027414,"owners_count":19736210,"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-07-30T20:01:02.828Z","updated_at":"2026-01-11T16:52:53.427Z","avatar_url":"https://github.com/bandwidth-throttle.png","language":"PHP","funding_links":[],"categories":["Uncategorized","PHP"],"sub_categories":["Uncategorized"],"readme":"# Token Bucket\n\nThis is a threadsafe implementation of the [Token Bucket algorithm](https://en.wikipedia.org/wiki/Token_bucket)\nin PHP. You can use a token bucket to limit an usage rate for a resource \n(e.g. a stream bandwidth or an API usage).\n\nThe token bucket is an abstract metaphor which doesn't have a direction of\nthe resource consumption. I.e. you can limit a rate for consuming or producing.\nE.g. you can limit the consumption rate of a third party API service, or you\ncan limit the usage rate of your own API service.\n\n# Installation\n\nUse [Composer](https://getcomposer.org/):\n\n```sh\ncomposer require bandwidth-throttle/token-bucket\n```\n\n# Usage\n\nThe package is in the namespace\n[`bandwidthThrottle\\tokenBucket`](http://bandwidth-throttle.github.io/token-bucket/api/namespace-bandwidthThrottle.tokenBucket.html).\n\n## Example\n\nThis example will limit the rate of a global resource to 10 requests per second\nfor all requests.\n\n```php\nuse bandwidthThrottle\\tokenBucket\\Rate;\nuse bandwidthThrottle\\tokenBucket\\TokenBucket;\nuse bandwidthThrottle\\tokenBucket\\storage\\FileStorage;\n\n$storage = new FileStorage(__DIR__ . \"/api.bucket\");\n$rate    = new Rate(10, Rate::SECOND);\n$bucket  = new TokenBucket(10, $rate, $storage);\n$bucket-\u003ebootstrap(10);\n\nif (!$bucket-\u003econsume(1, $seconds)) {\n    http_response_code(429);\n    header(sprintf(\"Retry-After: %d\", floor($seconds)));\n    exit();\n}\n\necho \"API response\";\n```\n\nNote: In this example `TokenBucket::bootstrap()` is part of the code. This is\nnot recommended for production, as this is producing unnecessary storage\ncommunication. `TokenBucket::bootstrap()` should be part of the application's\nbootstrap or deploy process.\n\n## Scope of the storage\n\nFirst you need to decide the scope of your resource. I.e. do you want to limit\nit per request, per user or amongst all requests? You can do this by choosing a\n[`Storage`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.storage.Storage.html)\nimplementation of the desired scope:\n\n- The [`RequestScope`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.storage.scope.RequestScope.html)\nlimits the rate only within one request. E.g. to limit the bandwidth of a download.\nEach requests will have the same bandwidth limit.\n\n- The [`SessionScope`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.storage.scope.SessionScope.html)\nlimits the rate of a resource within a session. The rate is controlled over\nall requests of one session. E.g. to limit the API usage per user.\n\n- The [`GlobalScope`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.storage.scope.GlobalScope.html)\nlimits the rate of a resource for all processes (i.e. requests). E.g. to limit\nthe aggregated download bandwidth of a resource over all processes. This scope\npermits race conditions between processes. The TokenBucket is therefore\nsynchronized on a shared mutex.\n\n## TokenBucket\n\nWhen you have your storage you can finally instantiate a\n[`TokenBucket`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.TokenBucket.html).\nThe first parameter is the capacity of the bucket. I.e. there will be never\nmore tokens available. This also means that consuming more tokens than the\ncapacity is invalid.\n\nThe second parameter is the token-add-[`Rate`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.Rate.html).\nIt determines the speed for filling the bucket with tokens. The rate is the\namount of tokens added per unit, e.g. `new Rate(100, Rate::SECOND)`\nwould add 100 tokens per second.\n\nThe third parameter is the storage, which is used to persist the token amount\nof the bucket. The storage does determine the scope of the bucket.\n\n### Bootstrapping\n\nA token bucket needs to be bootstrapped. While the method\n[`TokenBucket::bootstrap()`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.TokenBucket.html#_bootstrap)\ndoesn't have any side effects on an already bootstrapped bucket, it is not\nrecommended do call it for every request. Better include that in your\napplication's bootstrap or deploy process.\n\n### Consuming\n\nNow that you have a bootstrapped bucket, you can start consuming tokens. The\nmethod [`TokenBucket::consume()`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.TokenBucket.html#_consume)\nwill either return `true` if the tokens were consumed or `false` else.\nIf the tokens were consumed your application can continue to serve the resource.\n\nElse if the tokens were not consumed you should not serve the resource.\nIn that case `consume()` did write a duration of seconds into its second parameter\n(which was passed by reference). This is the duration until sufficient\ntokens would be available.\n\n## BlockingConsumer\n\nIn the first example we did either serve the request or fail with the HTTP status\ncode 429. This is actually a very resource efficient way of throtteling API\nrequests as it doesn't reserve resources on your server.\n\nHowever sometimes\nit is desirable not to fail but instead wait a little bit and then continue\nserving the requests. You can do this by consuming the token bucket with\na [`BlockingConsumer`](http://bandwidth-throttle.github.io/token-bucket/api/class-bandwidthThrottle.tokenBucket.BlockingConsumer.html).\n\n```php\nuse bandwidthThrottle\\tokenBucket\\Rate;\nuse bandwidthThrottle\\tokenBucket\\TokenBucket;\nuse bandwidthThrottle\\tokenBucket\\BlockingConsumer;\nuse bandwidthThrottle\\tokenBucket\\storage\\FileStorage;\n\n$storage  = new FileStorage(__DIR__ . \"/api.bucket\");\n$rate     = new Rate(10, Rate::SECOND);\n$bucket   = new TokenBucket(10, $rate, $storage);\n$consumer = new BlockingConsumer($bucket);\n$bucket-\u003ebootstrap(10);\n\n// This will block until one token is available.\n$consumer-\u003econsume(1);\n\necho \"API response\";\n```\n\nThis will effectively limit the rate to 10 requests per seconds as well. But\nin this case the client has not to bother with the 429 error. Instead the\nconnection is just delayed to the desired rate.\n\n# License and authors\n\nThis project is free and under the WTFPL.\nResponsible for this project is Markus Malkusch markus@malkusch.de.\n\n## Donations\n\nIf you like this project and feel generous donate a few Bitcoins here:\n[1335STSwu9hST4vcMRppEPgENMHD2r1REK](bitcoin:1335STSwu9hST4vcMRppEPgENMHD2r1REK)\n\n[![Build Status](https://travis-ci.org/bandwidth-throttle/token-bucket.svg?branch=master)](https://travis-ci.org/bandwidth-throttle/token-bucket)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbandwidth-throttle%2Ftoken-bucket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbandwidth-throttle%2Ftoken-bucket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbandwidth-throttle%2Ftoken-bucket/lists"}