Created
April 19, 2024 11:55
-
-
Save aneessh18/cee4fc9935799c116a3dcea04306623f to your computer and use it in GitHub Desktop.
Rate Limiter Module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Rate Limiter Interface | |
*/ | |
package io.aneessh18.postmaninterview; | |
public interface RateLimiter { | |
boolean isAllowed(Request request); | |
} | |
/* | |
Request Model | |
*/ | |
package io.aneessh18.postmaninterview; | |
public class Request { | |
public long time; | |
public String msg; | |
public String userId; | |
} | |
/* | |
Rest API class | |
*/ | |
package io.aneessh18.postmaninterview; | |
import org.springframework.http.ResponseEntity; | |
import org.springframework.web.bind.annotation.GetMapping; | |
import org.springframework.web.bind.annotation.PathVariable; | |
import org.springframework.web.bind.annotation.RequestMapping; | |
import org.springframework.web.bind.annotation.RequestParam; | |
import org.springframework.web.bind.annotation.RestController; | |
@RestController | |
@RequestMapping("/v1/api") | |
public class Controller { | |
private final RateLimiter rateLimiter = new SlidingWindowRateLimiter(10, 10000); | |
private final RateLimiter userIdRateLimiter = new UserIdSlidingWindowRateLimiter(10, 10000); | |
@GetMapping("/echo-path/{path}") | |
public ResponseEntity<String> echo(@PathVariable("path") String path,@RequestParam(value = "param", required = false) String param){ | |
Request request = new Request(); | |
request.msg = "msg"; | |
if (rateLimiter.isAllowed(request)){ | |
return ResponseEntity.ok(String.format("Request to path %s with %s param", path, param)); | |
}else{ | |
return ResponseEntity.status(429).build(); | |
} | |
} | |
@GetMapping("/echo-user/{user}") | |
public ResponseEntity<String> echoUser(@PathVariable("user") String userId){ | |
Request request = new Request(); | |
request.msg = "msg"; | |
request.userId=userId; | |
if (userIdRateLimiter.isAllowed(request)){ | |
return ResponseEntity.ok(String.format("Request to path %s", userId)); | |
}else{ | |
return ResponseEntity.status(429).build(); | |
} | |
} | |
} | |
/* | |
Sliding Window Rate Limiter | |
*/ | |
package io.aneessh18.postmaninterview; | |
import java.util.ArrayDeque; | |
import java.util.Queue; | |
public class SlidingWindowRateLimiter implements RateLimiter { | |
private final int numRequests; | |
private final int window; | |
private final Queue<Request> queue = new ArrayDeque<>(); | |
public SlidingWindowRateLimiter(int numRequests, int window) { | |
this.numRequests = numRequests; | |
this.window = window; | |
} | |
@Override | |
public boolean isAllowed(Request request){ | |
long time = System.currentTimeMillis(); | |
// prune the queue | |
// list -> time-window | |
if(!queue.isEmpty() && queue.peek().time+window<=time){ | |
queue.poll(); | |
} | |
if(queue.size()< numRequests){ | |
request.time=time; | |
queue.add(request); | |
return true; | |
} else{ | |
return false; | |
} | |
} | |
} | |
/* | |
UserIdSlidingWindowRateLimiter | |
*/ | |
package io.aneessh18.postmaninterview; | |
import java.util.ArrayDeque; | |
import java.util.HashMap; | |
import java.util.Queue; | |
public class UserIdSlidingWindowRateLimiter implements RateLimiter{ | |
private final int numRequests; | |
private final int window; | |
private final HashMap<String, Queue<Request>> userQueue; | |
public UserIdSlidingWindowRateLimiter(int numRequests, int window) { | |
this.numRequests = numRequests; | |
this.window = window; | |
this.userQueue = new HashMap<>(); | |
} | |
@Override | |
public boolean isAllowed(Request request){ | |
String userId = request.userId; | |
userQueue.putIfAbsent(userId, new ArrayDeque<>()); | |
Queue<Request> queue = userQueue.get(userId); | |
long time = System.currentTimeMillis(); | |
// prune the queue | |
// list -> time-window | |
if(!queue.isEmpty() && queue.peek().time+window<=time){ | |
queue.poll(); | |
} | |
if(queue.size()< numRequests){ | |
request.time=time; | |
queue.add(request); | |
return true; | |
} else{ | |
return false; | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment