Created
June 25, 2020 15:47
-
-
Save visparashar/4fd3b4d34ed469c083e9ee0465604437 to your computer and use it in GitHub Desktop.
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
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