Skip to content

Commit 5fe7133

Browse files
authored
Merge pull request #82 from oslabs-beta/sh/sliding-window-log-spec
spec for sliding window log. closes #67
2 parents 160071b + 38d8f0d commit 5fe7133

File tree

3 files changed

+69
-2
lines changed

3 files changed

+69
-2
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,5 @@
5555
"dependencies": {
5656
"graphql": "^16.5.0",
5757
"ioredis": "^5.0.5"
58-
5958
}
60-
}
59+
}

src/@types/rateLimit.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export interface RedisWindow {
2929
fixedWindowStart: number;
3030
}
3131

32+
export type RedisLog = RedisBucket[];
33+
3234
export type RateLimiterSelection =
3335
| 'TOKEN_BUCKET'
3436
| 'LEAKY_BUCKET'
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Redis from 'ioredis';
2+
import { RateLimiter, RateLimiterResponse } from '../@types/rateLimit';
3+
4+
/**
5+
* The SlidingWindowLog instance of a RateLimiter limits requests based on a unique user ID.
6+
* With the FixedWindow algorithm, users are able to send more requests to go through at the
7+
* edges of a window. The SlidingWindowLog algorithm addresses this issue by tracking request
8+
* timestamps in a log then removing these requests from the log once they fall outside of the window.
9+
* If a request is received and there are more than capacity requests in the log then the request is dropped
10+
*
11+
* Whenever a user makes a request the following steps are performed:
12+
* 1. The user's log is obtained from redis.
13+
* 2. Any requests that are older than window size are dropped from the log.
14+
* 3. The complexity of the current request is added to the complexity of all requests in the log.
15+
* 4. If the request exceeds the specified capacity it is dropped.
16+
* 5. Otherwise the request is allowed and ther current request is added to the log.
17+
*/
18+
class SlidingWindowLog implements RateLimiter {
19+
private windowSize: number;
20+
21+
private capacity: number;
22+
23+
private client: Redis;
24+
25+
/**
26+
* Create a new instance of a SlidingWindowLog rate limiter that can be connected to any redis store
27+
* @param windowSize size of window in milliseconds
28+
* @param capacity max number of tokens allowed in each window
29+
* @param client redis client where rate limiter will cache information
30+
*/
31+
constructor(windowSize: number, capacity: number, client: Redis) {
32+
this.windowSize = windowSize;
33+
this.capacity = capacity;
34+
this.client = client;
35+
if (windowSize <= 0 || capacity <= 0)
36+
throw SyntaxError('SlidingWindowLog windowSize and capacity must be positive');
37+
}
38+
39+
/**
40+
* @param {string} uuid - unique identifer used to throttle requests
41+
* @param {number} timestamp - time the request was recieved
42+
* @param {number} [tokens=1] - complexity of the query for throttling requests
43+
* @return {*} {Promise<RateLimiterResponse>}
44+
* @memberof SlidingWindowLog
45+
*/
46+
async processRequest(
47+
uuid: string,
48+
timestamp: number,
49+
tokens = 1
50+
): Promise<RateLimiterResponse> {
51+
// set the expiry of key-value pairs in the cache to 24 hours
52+
const keyExpiry = 86400000; // TODO: Make this a global for consistency across each algo.
53+
if (tokens > this.capacity) return { success: false, tokens: this.capacity };
54+
55+
throw new Error('SlidingWindowLog.processRequest not implemented');
56+
}
57+
58+
/**
59+
* Resets the rate limiter to the intial state by clearing the redis store.
60+
*/
61+
public reset(): void {
62+
this.client.flushall();
63+
}
64+
}
65+
66+
export default SlidingWindowLog;

0 commit comments

Comments
 (0)