package au.com.vaadinutils.errorHandling; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import com.google.common.base.Stopwatch; public class ErrorRateController { final LinkedBlockingQueue<Boolean> availablePermits = new LinkedBlockingQueue<>(); final Stopwatch lastCreated = Stopwatch.createStarted(); private long maxBurst; private double permitRate; private TimeUnit permitRateUnits; /** * * @param maxBurst * - maximum of permits that will be stockpiled for a burst after * a period of less or activity * @param permitRate * - rate at which permits become available per permitRateUnits * @param permitRateUnits */ ErrorRateController(long maxBurst, double permitRate, TimeUnit permitRateUnits) { this.maxBurst = maxBurst; this.permitRate = permitRate; this.permitRateUnits = permitRateUnits; // fill the availablePermits for (int i = 0; i < maxBurst; i++) { availablePermits.add(true); } } /** * returns true if able to acquire a permit, more specifically true if the rate has not been exceeded. * @return */ public boolean acquire() { Boolean permit = availablePermits.poll(); if (permit == null) { long permitsToAdd = 0; synchronized (lastCreated) { permitsToAdd = Math.min(maxBurst, (long) (lastCreated.elapsed(permitRateUnits) * permitRate)); if (permitsToAdd > 0) { lastCreated.reset(); lastCreated.start(); permit = true; } } for (int i = 0; i < permitsToAdd-1; i++) { availablePermits.add(true); } // if (permitsToAdd > 0) // { // logger.info("Added " + permitsToAdd); // } } return permit != null; } }