Skip to content

Instantly share code, notes, and snippets.

@pkafel
Last active September 20, 2023 20:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pkafel/18d55e6c8aa0cf84251ea60d7f2a9c71 to your computer and use it in GitHub Desktop.
Save pkafel/18d55e6c8aa0cf84251ea60d7f2a9c71 to your computer and use it in GitHub Desktop.
package com.piotrkafel.ratelimiter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class DifferentFixedWindowRateLimiter<T> {
private final int windowMaxSize;
private final Map<T, Window> store = new ConcurrentHashMap<>();
private final long windowSizeInMillies;
public DifferentFixedWindowRateLimiter(int windowMaxSize, long timeValue, TimeUnit timeUnit) {
if(windowMaxSize < 1) throw new IllegalArgumentException("Window size cannot be smaller than 1");
this.windowMaxSize = windowMaxSize;
this.windowSizeInMillies = timeUnit.toMillis(timeValue);
}
public boolean handleRequest(T key) {
// for now I assume System.currentTimeMillis() returns monotonic clock (even though it does not)
final long currentTimeMillis = System.currentTimeMillis();
final Window window = store.computeIfAbsent(key, k -> new Window(currentTimeMillis));
// synchronizing on window for better performance (instead of on the method)
synchronized (window) {
// check if we are in another window
if(currentTimeMillis - window.getBeginOfWindowInMillis() > windowSizeInMillies) {
// reset to new window
window.resetWindowWithNewBegin(currentTimeMillis, 1);
return true;
}
// check if number of requests + 1 is below threshold
if(window.getNumberOfRequests() + 1 <= windowMaxSize) {
window.increaseNumberOfRequests();
return true;
}
return false;
}
}
public class Window {
private int numberOfRequests;
private long beginOfWindowInMillis;
public Window(long beginOfWindowInMillis) {
resetWindowWithNewBegin(beginOfWindowInMillis, 0);
}
public int getNumberOfRequests() {
return numberOfRequests;
}
public long getBeginOfWindowInMillis() {
return beginOfWindowInMillis;
}
public void resetWindowWithNewBegin(long beginOfWindowInMillis, int numberOfRequests) {
this.beginOfWindowInMillis = beginOfWindowInMillis;
this.numberOfRequests = numberOfRequests;
}
public void increaseNumberOfRequests() {
this.numberOfRequests++;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment