Skip to content

Commit 5b7366c

Browse files
authored
Merge pull request #140 from BrianLusina/feat/design-request-logger-rate-limiter
feat(design, request-logger): logger rate limiter
2 parents 8f7d65b + 64542d2 commit 5b7366c

12 files changed

+135
-0
lines changed

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,8 @@
514514
* Pubsub
515515
* Simple Events
516516
* [Test Simple Events](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/pubsub/simple_events/test_simple_events.py)
517+
* Request Logger
518+
* [Test Request Logger](https://github.com/BrianLusina/PythonSnips/blob/master/design_patterns/request_logger/test_request_logger.py)
517519
* Structural
518520
* Proxy
519521
* Subject
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Logger Rate Limiter
2+
3+
For the given stream of message requests and their timestamps as input, you must implement a logger rate limiter system
4+
that decides whether the current message request is displayed. The decision depends on whether the same message has
5+
already been displayed in the last S seconds. If yes, then the decision is FALSE, as this message is considered a
6+
duplicate. Otherwise, the decision is TRUE.
7+
8+
> Note: Several message requests, though received at different timestamps, may carry identical messages.
9+
10+
## Constraints
11+
12+
- 1 <= `request.length` <= 10^2
13+
- 0 <= `timestamp` <= 10^3
14+
- Timestamps are in ascending order.
15+
- Messages can be written in lowercase or uppercase English alphabets.
16+
17+
## Examples
18+
19+
![Example 1](./images/examples/request_logger_example_1.png)
20+
![Example 2](./images/examples/request_logger_example_2.png)
21+
![Example 3](./images/examples/request_logger_example_3.png)
22+
23+
## Solution
24+
25+
We need to know if a message already exists and keep track of its time limit. When thinking about such problems where
26+
two associated values need to be checked, we can use a hash map.
27+
28+
We can use all incoming messages as keys and their respective time limits as values. This will help us eliminate
29+
duplicates and respect the time limit of S seconds as well.
30+
31+
Here is how we’ll implement our algorithm using hash maps:
32+
33+
1. Initialize a hash map.
34+
2. When a request arrives, check if it’s a new request (the message is not among the keys stored in the hash map) or a
35+
repeated request (an entry for this message already exists in the hash map). If it’s a new request, accept it and add
36+
it to the hash map.
37+
3. If it’s a repeated request, compare the difference between the timestamp of the incoming request and the timestamp of
38+
the previous request with the same message. If this difference is greater than the time limit, S, accept it and
39+
update the timestamp for that specific message in the hash map. Otherwise, reject it.
40+
41+
![Solution 1](./images/solutions/request_logger_solution_1.png)
42+
![Solution 2](./images/solutions/request_logger_solution_2.png)
43+
![Solution 3](./images/solutions/request_logger_solution_3.png)
44+
![Solution 4](./images/solutions/request_logger_solution_4.png)
45+
![Solution 5](./images/solutions/request_logger_solution_5.png)
46+
47+
### Solution Summary
48+
49+
Let’s summarize our optimized algorithm:
50+
51+
1. After initializing a hash map, whenever a request arrives, we check whether it’s a new request or a repeated request
52+
after the assigned time limit
53+
54+
2. If the request meets either of the conditions mentioned in the above step, we accept and update the entry associated
55+
with that specific request in the hash map. Otherwise, reject the request and return the final decision.
56+
57+
### Time Complexity
58+
59+
The decision function checks whether a message has already been encountered, and if so, how long ago it was encountered.
60+
Thanks to the use of hash maps, both operations are completed in constant time—therefore, the time complexity of the
61+
decision function is O(1).
62+
63+
### Space Complexity
64+
65+
The space complexity of the algorithm is O(n), where n is the number of incoming requests that we store.
66+
67+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import Dict
2+
3+
4+
class RequestLogger:
5+
def __init__(self, time_limit: int):
6+
self.time_limit = time_limit
7+
# keeps track of the requests as they come in key value pairs, which allows for first lookups (O(1)).
8+
# the key is the request, the value is the time.
9+
self.request_map: Dict[str, int] = {}
10+
11+
# This function decides whether the message request should be accepted or rejected
12+
def message_request_decision(self, timestamp: int, request: str) -> bool:
13+
formatted_message = request.lower()
14+
if formatted_message in self.request_map:
15+
latest_time_for_message = self.request_map[formatted_message]
16+
difference = timestamp - latest_time_for_message
17+
if difference < self.time_limit:
18+
return False
19+
self.request_map[formatted_message] = timestamp
20+
return True
21+
22+
self.request_map[formatted_message] = timestamp
23+
return True
99 KB
Loading
96 KB
Loading
104 KB
Loading
95.4 KB
Loading
61.9 KB
Loading
81.7 KB
Loading
100 KB
Loading

0 commit comments

Comments
 (0)