Skip to content

Commit fba79c0

Browse files
Yufei WuYufei Wu
authored andcommitted
updated fixed window algo and test cases
1 parent 0d2832f commit fba79c0

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

src/rateLimiters/fixedWindow.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,18 @@ class FixedWindow implements RateLimiter {
8383
}
8484
const window: RedisWindow = await JSON.parse(windowJSON);
8585

86+
const updatedUserWindow = this.updateTimeWindow(window, timestamp);
87+
updatedUserWindow.currentTokens += tokens;
8688
// update the currentToken until reaches its capacity
87-
window.currentTokens += tokens;
88-
if (window.currentTokens > this.capacity) {
89-
window.currentTokens = this.capacity;
89+
if (updatedUserWindow.currentTokens > this.capacity) {
90+
updatedUserWindow.currentTokens -= tokens;
9091
return {
9192
success: false,
92-
tokens: this.capacity - window.currentTokens,
93+
tokens: this.capacity - updatedUserWindow.currentTokens,
9394
};
9495
}
9596

9697
// update a new time window, check the current capacity situation
97-
const updatedUserWindow = this.updateTimeWindow(window, timestamp);
9898
if (tokens > this.capacity) {
9999
await this.client.setex(uuid, keyExpiry, JSON.stringify(updatedUserWindow));
100100
return { success: false, tokens: this.capacity };
@@ -119,8 +119,13 @@ class FixedWindow implements RateLimiter {
119119
fixedWindowStart: window.fixedWindowStart,
120120
};
121121
if (timestamp >= window.fixedWindowStart + this.windowSize) {
122-
updatedUserWindow.fixedWindowStart = window.fixedWindowStart + this.windowSize;
123-
updatedUserWindow.currentTokens = 0;
122+
if (timestamp >= window.fixedWindowStart + this.windowSize * 2) {
123+
updatedUserWindow.fixedWindowStart = timestamp;
124+
updatedUserWindow.currentTokens = 0;
125+
} else {
126+
updatedUserWindow.fixedWindowStart = window.fixedWindowStart + this.windowSize;
127+
updatedUserWindow.currentTokens = 0;
128+
}
124129
}
125130
return updatedUserWindow;
126131
};

test/rateLimiters/fixedWindow.test.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe('Test FixedWindow Rate Limiter', () => {
7272
).toBe(false);
7373
expect(
7474
(await limiter.processRequest(user2, timestamp, partialWithdraw)).tokens
75-
).toBe(0);
75+
).toBe(4);
7676
});
7777
});
7878
describe('after a BLOCKED request...', () => {
@@ -93,7 +93,7 @@ describe('Test FixedWindow Rate Limiter', () => {
9393
const result = await limiter.processRequest(user2, timestamp + WINDOW_SIZE - 1, 2);
9494

9595
expect(result.success).toBe(false);
96-
expect(result.tokens).toBe(0);
96+
expect(result.tokens).toBe(1);
9797

9898
// expect current tokens in the window to still be 9
9999
expect((await getWindowFromClient(client, user2)).currentTokens).toBe(9);
@@ -109,19 +109,44 @@ describe('Test FixedWindow Rate Limiter', () => {
109109
const noAccess = await limiter.processRequest(
110110
user3,
111111
timestamp + WINDOW_SIZE - 1,
112-
1
112+
2
113113
);
114114

115-
// expect cannot pass any request
115+
// expect not passing any request
116116
expect(noAccess.tokens).toBe(0);
117117
expect(noAccess.success).toBe(false);
118118

119-
const newRequest = 3;
120-
await setTokenCountInClient(client, user3, newRequest, timestamp + WINDOW_SIZE + 1);
121-
const newAccess = await limiter.processRequest(user3, timestamp, 1);
119+
const newRequest = 1;
120+
expect(
121+
(await limiter.processRequest(user3, timestamp + WINDOW_SIZE, newRequest))
122+
.success
123+
).toBe(true);
124+
const count = await getWindowFromClient(client, user3);
125+
expect(count.currentTokens).toBe(1);
126+
});
127+
test('Request will be passed after two window sizes', async () => {
128+
const fullRequest = 10;
129+
await setTokenCountInClient(client, user3, fullRequest, timestamp);
130+
const noAccess = await limiter.processRequest(
131+
user3,
132+
timestamp + WINDOW_SIZE - 1,
133+
2
134+
);
135+
136+
// expect not passing any request
137+
expect(noAccess.tokens).toBe(0);
138+
expect(noAccess.success).toBe(false);
139+
140+
const newRequest = 6;
141+
// check if current time is over one window size
142+
const newAccess = await limiter.processRequest(
143+
user3,
144+
timestamp + WINDOW_SIZE * 2,
145+
newRequest
146+
);
122147

148+
expect(newAccess.tokens).toBe(4);
123149
expect(newAccess.success).toBe(true);
124-
expect(newAccess.tokens).toBe(6);
125150
});
126151
});
127152
});

0 commit comments

Comments
 (0)