Skip to content

Instantly share code, notes, and snippets.

@JakubGraczyk
Created December 15, 2018 21:27
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 JakubGraczyk/6d178a61bb81b9a98b95ce2d3d28cd33 to your computer and use it in GitHub Desktop.
Save JakubGraczyk/6d178a61bb81b9a98b95ce2d3d28cd33 to your computer and use it in GitHub Desktop.
package main;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class RequestsLimiter {
private int maxNumberOFRequestsFromSingleUser;
private long waitTimeInMillis;
private Semaphore usersLimiter;
private Semaphore requestsLimiter;
private ConcurrentHashMap<String, Semaphore> requestsPerUserLimiter = new ConcurrentHashMap<>();
public RequestsLimiter(int maxNumberOfUsers, int maxNumberOFRequestsPerUser, int maxNumberOfRequests, long waitTimeInMillis) {
usersLimiter = new Semaphore(maxNumberOfUsers);
this.maxNumberOFRequestsFromSingleUser = maxNumberOFRequestsPerUser;
requestsLimiter = new Semaphore(maxNumberOfRequests);
this.waitTimeInMillis = waitTimeInMillis;
}
public boolean work(String user) throws InterruptedException {
long startTime = new Date().getTime();
if (tryLogin(user) && tryPassRequestFromUser(user, startTime) && trySendRequest(user, startTime)) {
TimeUnit.MILLISECONDS.sleep((int) (Math.random() * 2000));
return true;
} else {
return false;
}
}
private boolean trySendRequest(String user, long startTime) throws InterruptedException {
try {
return checkIfRequestCanBeSend(startTime);
} finally {
requestsLimiter.release();
}
}
private boolean tryPassRequestFromUser(String user, long startTime) throws InterruptedException {
try {
return checkIfUserCanGenerateRequest(user, startTime);
} finally {
releaseSlotForGivenUser(user);
}
}
private boolean tryLogin(String user) throws InterruptedException {
if (requestsPerUserLimiter.containsKey(user)) {
return true;
} else {
return usersLimiter.tryAcquire(waitTimeInMillis, TimeUnit.MILLISECONDS);
}
}
private boolean checkIfUserCanGenerateRequest(String user, long startTime) throws InterruptedException {
if (!requestsPerUserLimiter.containsKey(user))
requestsPerUserLimiter.put(user, new Semaphore(maxNumberOFRequestsFromSingleUser));
return requestsPerUserLimiter.get(user).tryAcquire(waitTimeInMillis - (new Date().getTime() - startTime), TimeUnit.MILLISECONDS);
}
private boolean checkIfRequestCanBeSend(long startTime) throws InterruptedException {
return requestsLimiter.tryAcquire(waitTimeInMillis - (new Date().getTime() - startTime), TimeUnit.MILLISECONDS);
}
private void releaseSlotForGivenUser(String user) {
requestsPerUserLimiter.get(user).release();
if (requestsPerUserLimiter.get(user).availablePermits() == maxNumberOFRequestsFromSingleUser) {
requestsPerUserLimiter.remove(user);
usersLimiter.release();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment