Skip to content

Instantly share code, notes, and snippets.

@StanSvec
Created May 23, 2024 14:19
Show Gist options
  • Save StanSvec/c6eb395fafea34833efb56c68d85a771 to your computer and use it in GitHub Desktop.
Save StanSvec/c6eb395fafea34833efb56c68d85a771 to your computer and use it in GitHub Desktop.
Work limiter for Java
import java.util.concurrent.TimeUnit
import static java.util.Arrays.asList
import static java.util.concurrent.TimeUnit.MILLISECONDS
/**
* Limit amount of work according to the provided frequency limitations
*
* Note: Converted from Java
*/
class WorkLimiter {
private final List<FreqLimit> limits
private final long startTimestamp
private final SortedMap<Long, Integer> timestampToWorkCount
WorkLimiter(FreqLimit... limits) {
this(asList(limits))
}
WorkLimiter(List<FreqLimit> limits) {
this.limits = new ArrayList<>(limits)
this.startTimestamp = System.currentTimeMillis()
this.timestampToWorkCount = new TreeMap<>()
}
/**
* Record single (unit of) work and put the thread into sleep in case any of the limits has been reached in its current interval.
* The thread will sleep as long as it cannot do the work due to any of the limits.
*
* @throws InterruptedException if the sleeping thread is interrupted
*/
void limit() throws InterruptedException {
long finished = System.currentTimeMillis()
timestampToWorkCount.merge(finished, 1, Integer::sum)
for (FreqLimit limit : limits) {
long elapsedInWin = (finished - startTimestamp) % limit.inMillis()
long winStart = finished - elapsedInWin
int workInWin = timestampToWorkCount.tailMap(winStart).values().stream().mapToInt(Integer::intValue).sum()
if (workInWin == limit.limit) {
Thread.sleep(limit.inMillis() - elapsedInWin)
}
}
}
static class FreqLimit {
private final int freqValue
private final TimeUnit freqUnit
private final int limit
FreqLimit(int freqValue, TimeUnit freqUnit, int limit) {
this.freqValue = freqValue
this.freqUnit = freqUnit
this.limit = limit
}
private long inMillis() {
return MILLISECONDS.convert(freqValue, freqUnit)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment