← Усі задачіNode.js · Middle

Обмежувач частоти token bucket

Напишіть createTokenBucket({ capacity, refillPerSecond, now }). Відро починає повним (capacity токенів) і поповнюється на refillPerSecond токенів за секунду, але не більше за capacity. Метод take() забирає один токен і повертає true, а якщо цілого токена немає - false (запит відхиляється з 429). tokens() повертає кількість цілих токенів.

Час береться з now() у мілісекундах - так обмежувач можна тестувати без справжнього очікування. Поповнення неперервне: за 250 мс при 2 токенах на секунду набігає половина токена.

Тести (5)

  1. let t = 0;
    const bucket = createTokenBucket({ capacity: 3, refillPerSecond: 1, now: () => t });
    expect([bucket.take(), bucket.take(), bucket.take(), bucket.take()]).toEqual([true, true, true, false]);
  2. let t = 0;
    const bucket = createTokenBucket({ capacity: 2, refillPerSecond: 1, now: () => t });
    bucket.take(); bucket.take();
    expect(bucket.take()).toBe(false);
    t = 1000;
    expect(bucket.take()).toBe(true);
    expect(bucket.take()).toBe(false);
  3. let t = 0;
    const bucket = createTokenBucket({ capacity: 5, refillPerSecond: 2, now: () => t });
    for (let i = 0; i < 5; i++) bucket.take();
    t = 60_000;
    expect(bucket.tokens()).toBe(5);
  4. let t = 0;
    const bucket = createTokenBucket({ capacity: 1, refillPerSecond: 2, now: () => t });
    bucket.take();
    t = 250;
    expect(bucket.take()).toBe(false);
    t = 500;
    expect(bucket.take()).toBe(true);
  5. let t = 0;
    const bucket = createTokenBucket({ capacity: 10, refillPerSecond: 1, now: () => t });
    expect(bucket.tokens()).toBe(10);
    bucket.take(); bucket.take(); bucket.take();
    expect(bucket.tokens()).toBe(7);