All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sirius.kernel.commons.RateLimit Maven / Gradle / Ivy

Go to download

Provides common core classes and the microkernel powering all Sirius applications

There is a newer version: 12.9.1
Show newest version
/*
 * Made with all the love in the world
 * by scireum in Remshalden, Germany
 *
 * Copyright by scireum GmbH
 * http://www.scireum.de - [email protected]
 */

package sirius.kernel.commons;

import java.util.concurrent.TimeUnit;

/**
 * Limits calls to specified rate. Can be either time based, or invocation based.
 * 

* This method {@link #check()} can be called frequently. It will however only return true after a certain * amount of time has elapsed or after a number of calls where made. The mode depends on how the object was created. *

* As an example, this can be used in an inner loop if one wants to print out the current status every once in a while. * Since writing to System.out is comparatively slow, it's a good idea to apply a rate limit: *

 * {@code
 * RateLimit limit = RateLimit.everyNthCall(1000);
 * for(int i = 0; i < 100000; i++) {
 *     // ...smart computation here...
 *     if (limit.check()) {
 *          System.out.println(i);
 *     }
 * }
 * }
 * 
*/ public class RateLimit { private enum Mode { TIME_BASED, CALL_BASED } private final long interval; private final Mode mode; private final long permitsPerInterval; private volatile long state; private volatile long permits; /* * Use the static constructor static factory method */ private RateLimit(long interval, long permitsPerInterval, Mode mode) { this.interval = interval; this.permitsPerInterval = permitsPerInterval; this.mode = mode; if (mode == Mode.CALL_BASED) { state = interval; } else { state = System.currentTimeMillis(); } } /** * Creates a new call based rate limit. *

* Calling {@link #check()} on will only return true every n-th call and false otherwise. * * @param n the number of calls to skip (returning false) by {@link #check()} before true * is returned * @return a new call based rate limit */ public static RateLimit everyNthCall(long n) { return new RateLimit(n, 0, Mode.CALL_BASED); } /** * Creates a new time based rate limit. *

* Calling {@link #check()} on will only return true every after the given amount of time has be passed * since the last time it returned true. Returns false otherwise. * * @param interval the amount of time after a call to {@link #check()} returns true again * @param unit the unit for amount * @return a new time based rate limit */ public static RateLimit timeInterval(long interval, TimeUnit unit) { return nTimesPerInterval(interval, unit, 1); } /** * Creates a new time based rate limit which permits up to N calls per interval. *

* Calling {@link #check()} on will only return true N times in every given interval, * false otherwise. * * @param interval the amount of time after a call to {@link #check()} returns true again * @param unit the unit for amount * @param permitsPerInterval the number of times to return true per interval * @return a new time based rate limit */ public static RateLimit nTimesPerInterval(long interval, TimeUnit unit, int permitsPerInterval) { return new RateLimit(TimeUnit.MILLISECONDS.convert(interval, unit), permitsPerInterval, Mode.TIME_BASED); } /** * Checks whether the rate limit constraints permit another call or not. * * @return true if the call or time based rate limiting permit another call, flfalse otherwise */ public boolean check() { if (mode == Mode.CALL_BASED) { if (--state <= 0) { state = interval; return true; } } else { if (System.currentTimeMillis() - state > interval) { state = System.currentTimeMillis(); permits = permitsPerInterval; } return permits-- > 0; } return false; } @Override public String toString() { if (mode == Mode.CALL_BASED) { return Strings.apply("Every %d calls: %d to go...", interval, state); } long delta = interval - (System.currentTimeMillis() - state); if (delta > 0) { return Strings.apply("Every %d ms: %d ms to go...", interval, delta); } else { return Strings.apply("Every %d ms: Ready to go...", interval); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy