← Wszystkie zadaniaNode.js · Middle

Ogranicznik szybkości token bucket

Napisz createTokenBucket({ capacity, refillPerSecond, now }). Wiadro zaczyna pełne (capacity tokenów) i uzupełnia się o refillPerSecond tokenów na sekundę, ale nigdy ponad capacity. take() zabiera jeden token i zwraca true, a gdy nie ma całego tokena, zwraca false (żądanie odrzucane z 429). tokens() zwraca liczbę całych tokenów.

Czas pochodzi z now() w milisekundach, więc ogranicznik da się testować bez prawdziwego czekania. Uzupełnianie jest ciągłe: przy 2 tokenach na sekundę 250 ms dodaje pół tokena.

Testy (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);