StackAsk is a community where developers ask questions, share answers and learn from each others real-world experience, so every solved problem helps the next person who runs into it.
Bandwidth b = Bandwidth.classic(100, Refill.intervally(100, Duration.ofSeconds(5))); //Bandwidth b = Bandwidth.classic(100, Refill.intervally(100, Duration.ofMinutes(10))); Bucket bk = Bucket.builder().addLimit(b).build(); //then if(bk.tryConsume(1)) { //stuff } else { throw }
RateLimiterConfig config = RateLimiterConfig.custom() .limitRefreshPeriod(Duration.ofSeconds(5)) .limitForPeriod(100) .timeoutDuration(Duration.ofSeconds(1)) .build(); RateLimiterRegistry rateLimiterRegistry = RateLimiterRegistry.of(config); RateLimiter rateLimiterWithCustomConfig = rateLimiterRegistry .rateLimiter("name2", config); CheckedRunnable restrictedCall = RateLimiter .decorateCheckedRunnable(rateLimiterWithCustomConfig, this::doStuff); //then Try.run(restrictedCall).onFailure(this::throwEx)
public class EzyActionFrame5Seconds extends EzyActionFrame { public EzyActionFrameSecond() { this(Integer.MAX_VALUE); } public EzyActionFrameSecond(long maxActions) { super(maxActions); } public EzyActionFrameSecond(long maxActions, long startTime) { super(maxActions, startTime); } @Override protected final int getExistsTime() { return 5000; } @Override public final EzyActionFrame nextFrame() { return new EzyActionFrame5Seconds(maxActions, endTime); } }
frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 0, maxActions: 5, tooManyRequest: false add 1 actions frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 1, maxActions: 5, tooManyRequest: false add 2 actions frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 3, maxActions: 5, tooManyRequest: false add 7 actions frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 10, maxActions: 5, tooManyRequest: true add 8 actions frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 18, maxActions: 5, tooManyRequest: true add 5 actions frame[1]> EzyActionFrame5Seconds: 2022-10-14 15-39-19.701 -> 2022-10-14 15-39-24.701, actions: 23, maxActions: 5, tooManyRequest: true add 6 actions frame[2]> EzyActionFrame5Seconds: 2022-10-14 15-39-24.701 -> 2022-10-14 15-39-29.701, actions: 6, maxActions: 5, tooManyRequest: true add 2 actions frame[2]> EzyActionFrame5Seconds: 2022-10-14 15-39-24.701 -> 2022-10-14 15-39-29.701, actions: 8, maxActions: 5, tooManyRequest: true add 4 actions frame[2]> EzyActionFrame5Seconds: 2022-10-14 15-39-24.701 -> 2022-10-14 15-39-29.701, actions: 12, maxActions: 5, tooManyRequest: true add 2 actions frame[2]> EzyActionFrame5Seconds: 2022-10-14 15-39-24.701 -> 2022-10-14 15-39-29.701, actions: 14, maxActions: 5, tooManyRequest: true add 4 actions frame[2]> EzyActionFrame5Seconds: 2022-10-14 15-39-24.701 -> 2022-10-14 15-39-29.701, actions: 18, maxActions: 5, tooManyRequest: true add 8 actions frame[3]> EzyActionFrame5Seconds: 2022-10-14 15-39-29.701 -> 2022-10-14 15-39-34.701, actions: 8, maxActions: 5, tooManyRequest: true
public class EzyCompositeActionFrame { private final int seconds; private long totalActions; private final long maxActions; private final List inSecondFrames; public EzyCompositeActionFrame(int seconds, long maxActions) { this.seconds = seconds; this.maxActions = maxActions; this.inSecondFrames = new ArrayList<>(); } public synchronized boolean addActions(int actions) { final long currentTime = System.currentTimeMillis(); final long minStartTime = currentTime - seconds; final Iterator iterator = inSecondFrames.iterator(); while (iterator.hasNext()) { final EzyActionFrame frame = iterator.next(); if (frame.getStartTime() < minStartTime) { iterator.remove(); } else { break } } EzyActionFrame currentFrame = null for (EzyActionFrame frame : inSecondFrames) { if (frame.isValid()) { currentFrame = frame; break } } if (currentFrame == null) { currentFrame = new EzyActionFrameSecond(maxActions, currentTime); inSecondFrames.add(currentFrame); } currentFrame.addActions(actions); totalActions = inSecondFrames.stream().mapToLong(EzyActionFrame::getActions).sum(); return totalActions > maxActions; } public synchronized boolean isInvalid() {return totalActions > maxActions;} @Override public String toString() { final long startTime = inSecondFrames.isEmpty() ? System.currentTimeMillis() : inSecondFrames.get(0).startTime; final long endTime = startTime + seconds; final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS"); return df.format(startTime) + " -> " + df.format(endTime) + ", actions: " + totalActions + ", maxActions: " + maxActions + ", tooManyRequest: " + isInvalid(); } public static void main(String[] args) throws Exception { final EzyCompositeActionFrame frame = new EzyCompositeActionFrame(3, 4); System.out.println(frame); while (true) { final int actions = ThreadLocalRandom.current().nextInt(1, 10); System.out.println("add " + actions + " actions"); frame.addActions(actions); System.out.println(frame); Thread.sleep(1000); } } }
if(frame.isInvalid()) it should be if(frame.isValid()), right? But even so, the result is not my expectation.
package com.example.ratelimiting; import lombok.Getter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class EzyCompositeActionFrame { private final int seconds; private long totalActions; private final long maxActions; private final List<EzyActionFrame> inSecondFrames; public EzyCompositeActionFrame(int seconds, long maxActions) { this.seconds = seconds; this.maxActions = maxActions; this.inSecondFrames = new ArrayList<>(); } public synchronized boolean addActions(int actions) { final long currentTime = System.currentTimeMillis(); final long minStartTime = currentTime - seconds; final Iterator<EzyActionFrame> iterator = inSecondFrames.iterator(); while (iterator.hasNext()) { final EzyActionFrame frame = iterator.next(); if (frame.getStartTime() < minStartTime) { iterator.remove(); } else { break; } } EzyActionFrame currentFrame = null; for (EzyActionFrame frame : inSecondFrames) { if (frame.isValid()) { currentFrame = frame; break; } } if (currentFrame == null) { currentFrame = new EzyActionFrameSecond( maxActions, currentTime ); inSecondFrames.add(currentFrame); } currentFrame.addActions(actions); totalActions = inSecondFrames .stream() .mapToLong(EzyActionFrame::getActions) .sum(); return totalActions > maxActions; } public synchronized boolean isInvalid() { return totalActions > maxActions; } @Override public String toString() { final long startTime = inSecondFrames.isEmpty() ? System.currentTimeMillis() : inSecondFrames.get(0).startTime; final long endTime = startTime + seconds; final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS"); return df.format(startTime) + " -> " + df.format(endTime) + ", actions: " + totalActions + ", maxActions: " + maxActions + ", tooManyRequest: " + isInvalid(); } @Getter static abstract class EzyActionFrame { protected final long endTime; protected final long startTime; protected final long maxActions; protected volatile long actions; public EzyActionFrame(long maxActions) { this(maxActions, System.currentTimeMillis()); } public EzyActionFrame(long maxActions, long startTime) { this.maxActions = maxActions; this.startTime = startTime; this.endTime = startTime + getExistsTime(); } protected abstract int getExistsTime(); public boolean addActions(long actions) { return (this.actions += actions) > maxActions; } public boolean isExpired() { return System.currentTimeMillis() > endTime; } public boolean isInvalid() { return actions > maxActions; } public boolean isValid() { return !isInvalid(); } public abstract EzyActionFrame nextFrame(); @Override public String toString() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS"); return getClass().getSimpleName() + ": " + df.format(startTime) + " -> " + df.format(endTime); } } static class EzyActionFrameSecond extends EzyActionFrame { public EzyActionFrameSecond() { this(Integer.MAX_VALUE); } public EzyActionFrameSecond(long maxActions) { super(maxActions); } public EzyActionFrameSecond(long maxActions, long startTime) { super(maxActions, startTime); } @Override protected final int getExistsTime() { return 1000; } @Override public final EzyActionFrame nextFrame() { return new EzyActionFrameSecond(maxActions, endTime); } } public static void main(String[] args) throws Exception { final EzyCompositeActionFrame frame = new EzyCompositeActionFrame(3, 4); // 1st request comes (second ~0.5) Thread.sleep(500); System.out.println("add 1st actions"); frame.addActions(1); System.out.println(frame); // 2nd request comes (second ~1) Thread.sleep(450); System.out.println("add 2nd actions"); frame.addActions(2); System.out.println(frame); // 3th request comes (second ~2) Thread.sleep(1000); System.out.println("add 3th actions"); frame.addActions(3); System.out.println(frame); // 4th request comes (second ~3) Thread.sleep(1000); System.out.println("add 4th actions"); frame.addActions(4); System.out.println(frame); // 5th request comes (second ~4) Thread.sleep(1000); System.out.println("add 5th actions"); frame.addActions(5); System.out.println(frame); // 6th request comes (second ~4.1) Thread.sleep(100); System.out.println("add 6th actions"); frame.addActions(6); System.out.println(frame); // 7th request comes (second ~4.2) Thread.sleep(100); System.out.println("add 7th actions"); frame.addActions(7); System.out.println(frame); // 8th request comes (second ~4.3) Thread.sleep(100); System.out.println("add 8th actions"); frame.addActions(8); System.out.println(frame); } }
add 1st actions 2022-10-14 19-39-13.346 -> 2022-10-14 19-39-13.349, actions: 1, maxActions: 4, tooManyRequest: false add 2nd actions 2022-10-14 19-39-13.914 -> 2022-10-14 19-39-13.917, actions: 2, maxActions: 4, tooManyRequest: false add 3th actions 2022-10-14 19-39-14.927 -> 2022-10-14 19-39-14.930, actions: 3, maxActions: 4, tooManyRequest: false add 4th actions 2022-10-14 19-39-15.940 -> 2022-10-14 19-39-15.943, actions: 4, maxActions: 4, tooManyRequest: false add 5th actions 2022-10-14 19-39-16.953 -> 2022-10-14 19-39-16.956, actions: 5, maxActions: 4, tooManyRequest: true add 6th actions 2022-10-14 19-39-17.063 -> 2022-10-14 19-39-17.066, actions: 6, maxActions: 4, tooManyRequest: true add 7th actions 2022-10-14 19-39-17.172 -> 2022-10-14 19-39-17.175, actions: 7, maxActions: 4, tooManyRequest: true add 8th actions 2022-10-14 19-39-17.280 -> 2022-10-14 19-39-17.283, actions: 8, maxActions: 4, tooManyRequest: true
add 1st actions 2022-10-14 19-39-13.346 -> 2022-10-14 19-39-13.349, actions: 1, maxActions: 4, tooManyRequest: false add 2nd actions 2022-10-14 19-39-13.914 -> 2022-10-14 19-39-13.917, actions: 2, maxActions: 4, tooManyRequest: false add 3th actions 2022-10-14 19-39-14.927 -> 2022-10-14 19-39-14.930, actions: 3, maxActions: 4, tooManyRequest: false add 4th actions 2022-10-14 19-39-15.940 -> 2022-10-14 19-39-15.943, actions: 4, maxActions: 4, tooManyRequest: false add 5th actions 2022-10-14 19-39-16.953 -> 2022-10-14 19-39-16.956, actions: 5, maxActions: 4, tooManyRequest: false add 6th actions 2022-10-14 19-39-17.063 -> 2022-10-14 19-39-17.066, actions: 6, maxActions: 4, tooManyRequest: false add 7th actions 2022-10-14 19-39-17.172 -> 2022-10-14 19-39-17.175, actions: 7, maxActions: 4, tooManyRequest: false add 8th actions 2022-10-14 19-39-17.280 -> 2022-10-14 19-39-17.283, actions: 8, maxActions: 4, tooManyRequest: true
import lombok.Getter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class EzyCompositeActionFrame { private final int seconds; private volatile long totalActions; private final long maxActions; private final List inSecondFrames; public EzyCompositeActionFrame(int seconds, long maxActions) { this.seconds = seconds; this.maxActions = maxActions; this.inSecondFrames = new ArrayList<>(); } public synchronized boolean addActions(int actions) { final long currentTime = System.currentTimeMillis(); final long minStartTime = currentTime - seconds * 1000L final Iterator iterator = inSecondFrames.iterator(); while (iterator.hasNext()) { final EzyActionFrame frame = iterator.next(); if (frame.getStartTime() < minStartTime) { iterator.remove(); } else { break } } EzyActionFrame currentFrame = null for (EzyActionFrame frame : inSecondFrames) { if (frame.isValid()) { currentFrame = frame; break } } if (currentFrame == null) { currentFrame = new EzyActionFrameSecond(maxActions, currentTime); inSecondFrames.add(currentFrame); } currentFrame.addActions(actions); totalActions = inSecondFrames.stream().mapToLong(EzyActionFrame::getActions).sum(); return totalActions > maxActions; } public synchronized boolean isInvalid() {return totalActions > maxActions;} @Override public String toString() { final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS"); return df.format(System.currentTimeMillis()) + ", frames: " + inSecondFrames.size() + ", actions: " + totalActions + ", maxActions: " + maxActions + ", tooManyRequest: " + isInvalid(); } @Getter static abstract class EzyActionFrame { protected final long endTime; protected final long startTime; protected final long maxActions; protected volatile long actions; public EzyActionFrame(long maxActions) {this(maxActions, System.currentTimeMillis());} public EzyActionFrame(long maxActions, long startTime) { this.maxActions = maxActions; this.startTime = startTime; this.endTime = startTime + getExistsTime(); } protected abstract int getExistsTime() public boolean addActions(long actions) {return (this.actions += actions) > maxActions;} public boolean isExpired() {return System.currentTimeMillis() > endTime;} public boolean isInvalid() {return actions > maxActions;} public boolean isValid() {return !isInvalid();} public abstract EzyActionFrame nextFrame() @Override public String toString() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss.SSS"); return getClass().getSimpleName() + ": " + df.format(startTime) + " -> " + df.format(endTime); } } static class EzyActionFrameSecond extends EzyActionFrame { public EzyActionFrameSecond() {this(Integer.MAX_VALUE);} public EzyActionFrameSecond(long maxActions) {super(maxActions);} public EzyActionFrameSecond(long maxActions, long startTime) {super(maxActions, startTime);} @Override protected final int getExistsTime() {return 1000} @Override public final EzyActionFrame nextFrame() {return new EzyActionFrameSecond(maxActions, endTime);} } public static void main(String[] args) throws Exception { final EzyCompositeActionFrame frame = new EzyCompositeActionFrame(3, 4); // 1st request comes (second ~0.5) Thread.sleep(500); System.out.println("add 1st actions"); frame.addActions(1); System.out.println(frame); // 2nd request comes (second ~1) Thread.sleep(450); System.out.println("add 2nd actions"); frame.addActions(2); System.out.println(frame); // 3th request comes (second ~2) Thread.sleep(1000); System.out.println("add 3th actions"); frame.addActions(3); System.out.println(frame); // 4th request comes (second ~3) Thread.sleep(1000); System.out.println("add 4th actions"); frame.addActions(4); System.out.println(frame); // 5th request comes (second ~4) Thread.sleep(1000); System.out.println("add 5th actions"); frame.addActions(5); System.out.println(frame); // 6th request comes (second ~4.1) Thread.sleep(100); System.out.println("add 6th actions"); frame.addActions(6); System.out.println(frame); // 7th request comes (second ~4.2) Thread.sleep(100); System.out.println("add 7th actions"); frame.addActions(7); System.out.println(frame); // 8th request comes (second ~4.3) Thread.sleep(100); System.out.println("add 8th actions"); frame.addActions(8); System.out.println(frame); } }
2.2K Point(s)
1.2K Point(s)
313 Point(s)
178 Point(s)
138 Point(s)
Input your email to receive reset password link, or if you remember your password, you can click