Skip to content

Instantly share code, notes, and snippets.

@visparashar
Created June 25, 2020 15:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save visparashar/4fd3b4d34ed469c083e9ee0465604437 to your computer and use it in GitHub Desktop.
Save visparashar/4fd3b4d34ed469c083e9ee0465604437 to your computer and use it in GitHub Desktop.
public class RateLimiterDemo {
public static void main(String[] args) {
RateLimiter limiter = new RateLimiterImpl();
System.out.println("test1 " + limiter.accept("test1"));
System.out.println("test1 " +limiter.accept("test1"));
System.out.println("test1 " +limiter.accept("test1"));
System.out.println("test1 " +limiter.accept("test1"));
System.out.println("test2 " +limiter.accept("test2"));
System.out.println("test2 " +limiter.accept("test2"));
System.out.println("test2 " +limiter.accept("test2"));
System.out.println("test2 " +limiter.accept("test2"));
System.out.println("test1 " +limiter.accept("test1"));
}
}
class RateLimiterImpl implements RateLimiter{
private static long MINUTE_TIME_LIMIT=1000*60L;
private static long REQUEST_ALLOWED_PER_MINUTE=10000;
Queue<Long> q = new LinkedList<>();
private static int minuteLimit=100;
private Map<String, Optional<MyRateLimiter>> limiters = new ConcurrentHashMap<>();
@Override
public boolean accept(String clientId) {
if(!hit(System.currentTimeMillis())) {
return false;
}
Optional<MyRateLimiter> rateLimiter = getRateLimiter(clientId);
if(rateLimiter.isPresent()) {
boolean canAcquire= rateLimiter.get().tryAcquire();
if(canAcquire)
return q.add(System.currentTimeMillis());
}
return false;
}
private boolean hit(long timestamp) {
while(!q.isEmpty() && timestamp-q.peek() >= MINUTE_TIME_LIMIT) q.poll();
if(q.size() < REQUEST_ALLOWED_PER_MINUTE)
{
q.offer(timestamp);
return true;
}
return false;
}
private Optional<MyRateLimiter> getRateLimiter(String clientId) {
return limiters.computeIfAbsent(clientId, id -> {
return Optional.of(createRateLimiter(id));
});
}
private MyRateLimiter createRateLimiter(String clientId) {
return MyRateLimiter.create(minuteLimit, TimeUnit.MINUTES);
}
}
class MyRateLimiter {
private Semaphore semaphore;
private int maxPermits;
private TimeUnit timePeriod;
private ScheduledExecutorService scheduler;
public static MyRateLimiter create(int permits, TimeUnit timePeriod) {
MyRateLimiter limiter = new MyRateLimiter(permits, timePeriod);
limiter.schedulePermit();
return limiter;
}
private MyRateLimiter(int permits, TimeUnit timePeriod) {
this.semaphore = new Semaphore(permits);
this.maxPermits = permits;
this.timePeriod = timePeriod;
}
public boolean tryAcquire() {
return semaphore.tryAcquire();
}
public void stop() {
scheduler.shutdownNow();
}
public void schedulePermit() {
scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
semaphore.release(maxPermits - semaphore.availablePermits());
}, 0, 1, timePeriod);
}
}
interface RateLimiter{
boolean accept(String clientId);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment