Skip to content

Commit 8c8d9b0

Browse files
committed
Added RateLimiter algorithm.
1 parent 2800d0c commit 8c8d9b0

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

RateLimiter.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.cunningdj.grokJava;
2+
3+
import java.time.LocalDateTime;
4+
import java.util.LinkedList;
5+
import java.time.Duration;
6+
import java.time.Month;
7+
8+
class RateLimiter {
9+
private LinkedList<LocalDateTime> dtQueue;
10+
private final int SECONDS_PER_MINUTE = 60;
11+
public final int MAX_REQS_PER_MINUTE;
12+
// FOR TESTING ONLY (otherwise null)
13+
private final LocalDateTime CURRENT_DT_OVERRIDE;
14+
15+
public RateLimiter(int maxReqsPerMinute) {
16+
this.dtQueue = new LinkedList<>();
17+
this.MAX_REQS_PER_MINUTE = maxReqsPerMinute;
18+
this.CURRENT_DT_OVERRIDE = null;
19+
}
20+
21+
private RateLimiter(int maxReqsPerMinute, LocalDateTime currentDtOverride) {
22+
// FOR TESTING ONLY
23+
this.dtQueue = new LinkedList<>();
24+
this.MAX_REQS_PER_MINUTE = maxReqsPerMinute;
25+
this.CURRENT_DT_OVERRIDE = currentDtOverride;
26+
}
27+
28+
// MAIN
29+
public static void main(String[] args) {
30+
Tester tester = new Tester();
31+
String testTitle="";
32+
33+
// TEST CLASS METHODS HERE USING TESTER CLASS
34+
testTitle = "RATE_LIMITER";
35+
RateLimiter rl = new RateLimiter(3);
36+
tester.isTrue(rl.newRequest(new Request(RateLimiter.makeTestTime(10, 0))), testTitle);
37+
tester.isTrue(rl.newRequest(new Request(RateLimiter.makeTestTime(10, 20))), testTitle);
38+
tester.isTrue(rl.newRequest(new Request(RateLimiter.makeTestTime(10, 40))), testTitle);
39+
// False, and doesn't add it to the queue
40+
tester.isFalse(rl.newRequest(new Request(RateLimiter.makeTestTime(10, 59))), testTitle);
41+
// True; Skipoed the 10:59 request, and 10:00 request is now > 60s old, leaving 2 within the window during check
42+
tester.isTrue(rl.newRequest(new Request(RateLimiter.makeTestTime(11, 01))), testTitle);
43+
}
44+
45+
// PUBLIC
46+
public boolean newRequest(Request req) {
47+
if (dtQueue.size() == MAX_REQS_PER_MINUTE) {
48+
while (dtQueue.size() > 0
49+
&& Duration.between(dtQueue.peek(), req.dt).getSeconds() > SECONDS_PER_MINUTE) {
50+
dtQueue.poll();
51+
}
52+
}
53+
if (dtQueue.size() < MAX_REQS_PER_MINUTE) {
54+
dtQueue.add(req.dt);
55+
return true;
56+
} else {
57+
return false;
58+
}
59+
}
60+
61+
// PRIVATE
62+
// TEST ONLY
63+
private static LocalDateTime makeTestTime(int minutes, int seconds) {
64+
return LocalDateTime.of(2022, Month.MAY, 10, 10, minutes, seconds);
65+
}
66+
67+
// Request
68+
static class Request {
69+
public LocalDateTime dt;
70+
public Request() {
71+
this.dt = LocalDateTime.now();
72+
}
73+
74+
// TESTING ONLY
75+
private Request(LocalDateTime dt) {
76+
this.dt = dt;
77+
}
78+
}
79+
}

Tester.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ public void booleanEquals(boolean expected, boolean actual, String testTitle) {
8181
}
8282
}
8383

84+
public void isTrue(boolean actual, String testTitle) {
85+
booleanEquals(true, actual, testTitle);
86+
}
87+
88+
public void isFalse(boolean actual, String testTitle) {
89+
booleanEquals(false, actual, testTitle);
90+
}
91+
8492
public void listNodeEquals(ListNode expected, ListNode actual, String testTitle) {
8593
if (expected == actual) {
8694
printTestSuccess(testTitle);

0 commit comments

Comments
 (0)