Implementing a Leaky Bucket Rate Limiter
The leaky bucket algorithm is a common technique for rate limiting. It ensures that a system doesn't get overwhelmed by smoothing out incoming requests over time. This challenge asks you to implement a Python class that simulates a leaky bucket.
Problem Description
You need to create a Python class named LeakyBucket. This class will simulate the behavior of a leaky bucket, which has a fixed capacity and a constant leakage rate.
Here are the key requirements:
-
Initialization: The
LeakyBucketclass should be initialized with:capacity: The maximum number of items the bucket can hold.leak_rate: The number of items that leak out of the bucket per unit of time (e.g., per second).
-
Adding Items: The bucket should have a method, say
add(item), which attempts to add anitemto the bucket.- If the bucket has enough space (i.e.,
current_items < capacity), the item is added, and the method should returnTrue. - If the bucket is full, the item is rejected, and the method should return
False.
- If the bucket has enough space (i.e.,
-
Leaking: The bucket's contents should "leak" out at a constant
leak_rate. This leakage should be simulated over time. For simplicity in this challenge, we will consider time in discrete steps. Aleak()method should be implemented. Callingleak()should decrease the number of items in the bucket byleak_rate, ensuring that the number of items doesn't go below zero. -
Tracking Current Items: The class should maintain a count of the current number of items in the bucket.
Expected Behavior:
- When
add()is called and the bucket is not full, the item count increases. - When
add()is called and the bucket is full, the item count remains unchanged. - When
leak()is called, the item count decreases byleak_rate(or to zero if the current count is less thanleak_rate).
Edge Cases:
- Adding an item when the bucket is exactly full.
- Leaking when the bucket is empty or has fewer items than the
leak_rate. - Capacity being zero or negative (though we'll define constraints to avoid this).
- Leak rate being zero or negative (similarly, constraints will apply).
Examples
Example 1:
# Initializing a leaky bucket with capacity 5 and leak rate 2 per second.
bucket = LeakyBucket(capacity=5, leak_rate=2)
# Adding items
print(bucket.add(1)) # Output: True (bucket: 1)
print(bucket.add(2)) # Output: True (bucket: 2)
print(bucket.add(3)) # Output: True (bucket: 3)
# Simulating one second of leakage
bucket.leak() # bucket: 3 - 2 = 1
print(bucket.add(4)) # Output: True (bucket: 1 + 1 = 2)
print(bucket.add(5)) # Output: True (bucket: 2 + 1 = 3)
print(bucket.add(6)) # Output: True (bucket: 3 + 1 = 4)
print(bucket.add(7)) # Output: True (bucket: 4 + 1 = 5) - Bucket is now full
# Attempting to add when full
print(bucket.add(8)) # Output: False (bucket: 5)
# Simulating another second of leakage
bucket.leak() # bucket: 5 - 2 = 3
Explanation: The bucket starts empty. We add items until it's full. After a leak, there's space, allowing more items to be added until it's full again. Adding an item when full fails. Subsequent leakage reduces the count.
Example 2:
bucket = LeakyBucket(capacity=3, leak_rate=4)
print(bucket.add('a')) # Output: True (bucket: 1)
print(bucket.add('b')) # Output: True (bucket: 2)
print(bucket.add('c')) # Output: True (bucket: 3) - Bucket is full
# Attempting to add when full
print(bucket.add('d')) # Output: False (bucket: 3)
# Simulating leakage when leak_rate > current items
bucket.leak() # bucket: max(0, 3 - 4) = 0
print(bucket.add('e')) # Output: True (bucket: 1)
Explanation:
This demonstrates that the leak() method correctly handles cases where the leak_rate exceeds the current number of items, preventing the count from becoming negative.
Constraints
capacitywill be an integer,0 <= capacity <= 1000.leak_ratewill be an integer,0 <= leak_rate <= 100.- The
addandleakmethods will be called sequentially or interleaved, but the internal state should always reflect the correct number of items. - The internal tracking of items should not exceed the
capacity.
Notes
- Consider how you will manage the internal state of the bucket (the current number of items).
- The
leak_raterepresents items per "time unit". In this simulation, a call toleak()represents one time unit passing. - You can use simple integer arithmetic to manage the items.
- The
itemitself doesn't need to be stored in this simulation; we only need to track the count of items.