Skip to content
forked from greguz/porro

Fast leaky bucket algorithm implementation without timers for Node.js

License

Notifications You must be signed in to change notification settings

discue/leaky-buckets

 
 

Repository files navigation

npm version ci Coverage Status JavaScript Style Guide

Porro is a simple and fast implementation of the leaky bucket algorithm.

Naming things is hard

During a scene in Cloudy with a Chance of Meatballs 2, the protagonists are moving with a boat. At some point, a wild tribe of living leeks attacks the boat, and the scientist shouts: "There's a leak in the boat!". Porro means leek in Italian. Leaky bucket algorithm -> Leak -> Leek -> Porro.

Features

  • No dependencies: small footprint.
  • No timers: unlike some other implementations, Porro doesn't use any timer.
  • ES modules support: native Node.js import/export.
  • CommonJS support: common runtimes are still supported.
  • ES6: code just uses ES6 features.
  • TypeScript: this package includes its own TypeScript declarations.

Install

Open your favourite shell and run:

npm install porro

API

new Porro(options)

Porro's constructor.

  • options <Object>
    • bucketSize <Number> The size (number of tokens) of the bucket.
    • interval <Number> Time interval in milliseconds to refill the bucket.
    • tokensPerInterval <Number> Number of refilled tokens after the specified interval.
  • Returns: <Porro>

Porro::tokens

Returns (getter) the current number of tokens inside the bucket.

  • Returns: <Number>

Porro::request([quantity])

Returns the amount of time that the pending request needs to wait before executing.

  • [quantity] <Number> Number (positive integer) of tokens to burn for the current request. Defaults to 1.
  • Returns: <Number>

Porro::throttle([quantity])

Returns a Promise that will resolve when It's appropriate to execute the pending request.

  • [quantity] <Number> Number (positive integer) of tokens to burn for the current request. Defaults to 1.
  • Returns: <Promise> Resolves with the waited milliseconds.

Porro::reset()

Resets the bucket to its original status.

Example

import { Porro } from 'porro'

// 2 requests per second with a "buffer" of 5 requests
const bucket = new Porro({
  bucketSize: 5,
  interval: 1000,
  tokensPerInterval: 2
})

async function run () {
  // Create 10 "requests"
  const items = new Array(10).fill(null)

  // Execute all requests at the same time
  log('script is starting')
  await Promise.all(items.map(doSomething))
}

async function doSomething (value, index) {
  // Get the waiting time for the currenct request
  const ms = bucket.request()

  // Sleep for the required time
  // You can also use `await bucket.throttle()` for simplicity
  if (ms > 0) {
    log(`request #${index} will wait ${ms}ms`)
    await sleep(ms)
  }

  // Do something!
  log(`run request #${index}`)
}

function log (message) {
  console.log(`[${new Date().toISOString()}]`, message, `(bucket has now ${bucket.tokens} tokens)`)
}

function sleep (ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

run()
// [2023-01-27T14:21:13.776Z] script is starting (bucket has now 5 tokens)
// [2023-01-27T14:21:13.779Z] run request #0 (bucket has now 4 tokens)
// [2023-01-27T14:21:13.779Z] run request #1 (bucket has now 3 tokens)
// [2023-01-27T14:21:13.779Z] run request #2 (bucket has now 2 tokens)
// [2023-01-27T14:21:13.779Z] run request #3 (bucket has now 1 tokens)
// [2023-01-27T14:21:13.779Z] run request #4 (bucket has now 0 tokens)
// [2023-01-27T14:21:13.779Z] request #5 will wait 1000ms (bucket has now -1 tokens)
// [2023-01-27T14:21:13.779Z] request #6 will wait 1000ms (bucket has now -2 tokens)
// [2023-01-27T14:21:13.779Z] request #7 will wait 2000ms (bucket has now -3 tokens)
// [2023-01-27T14:21:13.780Z] request #8 will wait 2000ms (bucket has now -4 tokens)
// [2023-01-27T14:21:13.780Z] request #9 will wait 3000ms (bucket has now -5 tokens)
// [2023-01-27T14:21:14.782Z] run request #5 (bucket has now -3 tokens)
// [2023-01-27T14:21:14.782Z] run request #6 (bucket has now -3 tokens)
// [2023-01-27T14:21:15.779Z] run request #7 (bucket has now -1 tokens)
// [2023-01-27T14:21:15.780Z] run request #8 (bucket has now -1 tokens)
// [2023-01-27T14:21:16.782Z] run request #9 (bucket has now 1 tokens)

About

Fast leaky bucket algorithm implementation without timers for Node.js

Topics

Resources

License

Stars

Watchers

Forks

Languages

  • JavaScript 81.3%
  • TypeScript 14.8%
  • Shell 3.9%