Created
May 23, 2024 14:19
-
-
Save StanSvec/c6eb395fafea34833efb56c68d85a771 to your computer and use it in GitHub Desktop.
Work limiter for Java
This file contains hidden or 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
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