UNPKG

simple-token-bucket

Version:

A straightforward token bucket implementation with no entanglements

62 lines (43 loc) 3.28 kB
# simple-token-bucket Typescript token bucket implementation with no dependencies. ``` $ npm install --save simple-token-bucket ``` ```ts import { TokenBucket } from 'simple-token-bucket'; const bucket = new TokenBucket({ capacity: 10, fillQuantity: 1, fillTime: 1000, // in milliseconds initialCapacity: 0 }); const timeToWait = bucket.take(3); ``` ## Options * **capacity**: the capacity of the token bucket, aka burstiness * **fillQuantity**: how many tokens to add when filling * **fillTime**: how much time it takes to add fillQuantity tokens * **initialCapacity**: (optional) the bucket initializes to max capacity by default, but you can optionally change it here * **clock**: (optional) custom clock function `fillQuantity` and `fillTime` combined create a rate which is used to calculate both how many tokens to add at any given moment and how much time remains before a request can be fulfilled. I chose this approach since most of the time it's desirable to specify a rate limit in "X's per Y". ### A note on clocks Prior to version 3.0.0, this library used `Date.now()` to perform its calculations. This is problematic when the system clock changes, for example during DST adjustment or clock skew corrections deriving from NTP. As of version 3.0.0, `performance.now()` is used, which provides a monotonically-increasing time counter (at least up to some very large numbers). If you'd like different behavior, you can supply the `clock` option as a function which returns a `number`, e.g.: ```ts const bucket = new TokenBucket({ capacity: 10, fillQuantity: 1, fillTime: 1000, // in milliseconds clock: () => Date.now(), }); ``` ## Methods ### #take(N) Attempts to take N tokens from the bucket. Throws a `RangeError` if N exceeds the bucket's capacity. Returns 0 if successful, else returns the minimum number of milliseconds you must wait before the call will be successful. Note: This isn't a guarantee that the call *will* be successful, since other things might take from the bucket in the meantime! ## What A token bucket is a rate-limiting construct that requires no timers and uses a fixed amount of memory. Conceptually, every `fillTime` ms, `fillQuantity` "tokens" are added to an imaginary "bucket". When you want to do a thing, you attempt to remove one (or more) tokens from the bucket; if the bucket contains enough tokens, you may proceed, else you must fail. Token buckets can be used to reject a request from a source that is behaving too aggressively or as a building block for holding your own requests to some fixed rate, though in the latter case you may want to investigate the "leaky bucket" algorithm instead. Note: In this implementation, tokens are not locked to being added in groups of `fillQuantity`; instead, before each call to `take`, as many tokens are added to the bucket as possible given the time elapsed since the last attempt and the rate calculated by the two fill parameters. ## Why The token bucket implementations I found on NPM are either wrapped up in magic for applying rate limiting to things or not very robust. I wanted something to just "run the numbers" and give me the results, similar to what I did with [simple-backoff](https://www.npmjs.com/package/simple-backoff).