Description
This is a threadsafe implementation of the Token Bucket algorithm
in PHP. You can use a token bucket to limit an usage rate for a resource
(e.g. a stream bandwidth or an API usage).
The token bucket is an abstract metapher which doesn't have a direction of
the resource consumption. I.e. you can limit a rate for consuming or producing.
E.g. you can limit the consumption rate of a third party API service, or you
can limit the usage rate of your own API service.
Token Bucket alternatives and similar libraries
Based on the "Miscellaneous" category.
Alternatively, view Token Bucket alternatives based on common mentions on social networks and blogs.
-
Country List
:globe_with_meridians: List of all countries with names and ISO 3166-1 codes in all languages and data formats. -
Essence
Extracts information about web pages, like youtube videos, twitter statuses or blog articles. -
sabre/vobject
:date: The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects -
Lodash-PHP
Easy to use utility functions for everyday PHP projects. This is a port of the Lodash JS library to PHP -
Embera
A Oembed consumer library, that gives you information about urls. It helps you replace urls to youtube or vimeo for example, with their html embed code. It has advanced features like offline support, responsive embeds and caching support. -
Metrics
Simple library that abstracts different metrics collectors. I find this necessary to have a consistent and simple metrics (functional) API that doesn't cause vendor lock-in. -
ClassPreloader
Optimizes class loading performance by generating a single PHP file containing all of the autoloaded files. -
Cake Utility
[READ-ONLY] CakePHP Utility classes such as Inflector, Text, Hash, Security and Xml. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp -
RedisSessionHandler
An alternative Redis session handler for PHP featuring per-session locking and session fixation protection -
Yell
PHP package to make your objects strict and throw exception when you try to access or set some undefined property in your objects.
Cloudways' Black Friday Offer - 1st Choice of Developers
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Token Bucket or a related project?
README
Token Bucket
This is a threadsafe implementation of the Token Bucket algorithm in PHP. You can use a token bucket to limit an usage rate for a resource (e.g. a stream bandwidth or an API usage).
The token bucket is an abstract metaphor which doesn't have a direction of the resource consumption. I.e. you can limit a rate for consuming or producing. E.g. you can limit the consumption rate of a third party API service, or you can limit the usage rate of your own API service.
Installation
Use Composer:
composer require bandwidth-throttle/token-bucket
Usage
The package is in the namespace
bandwidthThrottle\tokenBucket
.
Example
This example will limit the rate of a global resource to 10 requests per second for all requests.
use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\storage\FileStorage;
$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate = new Rate(10, Rate::SECOND);
$bucket = new TokenBucket(10, $rate, $storage);
$bucket->bootstrap(10);
if (!$bucket->consume(1, $seconds)) {
http_response_code(429);
header(sprintf("Retry-After: %d", floor($seconds)));
exit();
}
echo "API response";
Note: In this example TokenBucket::bootstrap()
is part of the code. This is
not recommended for production, as this is producing unnecessary storage
communication. TokenBucket::bootstrap()
should be part of the application's
bootstrap or deploy process.
Scope of the storage
First you need to decide the scope of your resource. I.e. do you want to limit
it per request, per user or amongst all requests? You can do this by choosing a
Storage
implementation of the desired scope:
The
RequestScope
limits the rate only within one request. E.g. to limit the bandwidth of a download. Each requests will have the same bandwidth limit.The
SessionScope
limits the rate of a resource within a session. The rate is controlled over all requests of one session. E.g. to limit the API usage per user.The
GlobalScope
limits the rate of a resource for all processes (i.e. requests). E.g. to limit the aggregated download bandwidth of a resource over all processes. This scope permits race conditions between processes. The TokenBucket is therefore synchronized on a shared mutex.
TokenBucket
When you have your storage you can finally instantiate a
TokenBucket
.
The first parameter is the capacity of the bucket. I.e. there will be never
more tokens available. This also means that consuming more tokens than the
capacity is invalid.
The second parameter is the token-add-Rate
.
It determines the speed for filling the bucket with tokens. The rate is the
amount of tokens added per unit, e.g. new Rate(100, Rate::SECOND)
would add 100 tokens per second.
The third parameter is the storage, which is used to persist the token amount of the bucket. The storage does determine the scope of the bucket.
Bootstrapping
A token bucket needs to be bootstrapped. While the method
TokenBucket::bootstrap()
doesn't have any side effects on an already bootstrapped bucket, it is not
recommended do call it for every request. Better include that in your
application's bootstrap or deploy process.
Consuming
Now that you have a bootstrapped bucket, you can start consuming tokens. The
method TokenBucket::consume()
will either return true
if the tokens were consumed or false
else.
If the tokens were consumed your application can continue to serve the resource.
Else if the tokens were not consumed you should not serve the resource.
In that case consume()
did write a duration of seconds into its second parameter
(which was passed by reference). This is the duration until sufficient
tokens would be available.
BlockingConsumer
In the first example we did either serve the request or fail with the HTTP status code 429. This is actually a very resource efficient way of throtteling API requests as it doesn't reserve resources on your server.
However sometimes
it is desirable not to fail but instead wait a little bit and then continue
serving the requests. You can do this by consuming the token bucket with
a BlockingConsumer
.
use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\BlockingConsumer;
use bandwidthThrottle\tokenBucket\storage\FileStorage;
$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate = new Rate(10, Rate::SECOND);
$bucket = new TokenBucket(10, $rate, $storage);
$consumer = new BlockingConsumer($bucket);
$bucket->bootstrap(10);
// This will block until one token is available.
$consumer->consume(1);
echo "API response";
This will effectively limit the rate to 10 requests per seconds as well. But in this case the client has not to bother with the 429 error. Instead the connection is just delayed to the desired rate.
License and authors
This project is free and under the WTFPL. Responsible for this project is Markus Malkusch [email protected].
Donations
If you like this project and feel generous donate a few Bitcoins here: [1335STSwu9hST4vcMRppEPgENMHD2r1REK](bitcoin:1335STSwu9hST4vcMRppEPgENMHD2r1REK)
*Note that all licence references and agreements mentioned in the Token Bucket README section above
are relevant to that project's source code only.