Details

    • Type: New Feature
    • Status: Closed
    • Priority: Minor
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 5.2 M1
    • Component/s: Core
    • Labels:

      Description

      PoC:

      public class RateLimiter {
      
      	private static final Log logger = LogFactory.getLog(RateLimiter.class);
      
      	private final long interval;
      
      	private final long maxDelay;
      
      	private final AtomicLong nextRelease = new AtomicLong(0L);
      
      	/**
      	 * Create an instance with the provided arguments.
      	 * @param rate the rate per time unit.
      	 * @param maxDelay the max allowable delay in time units.
      	 * @param unit the time unit.
      	 */
      	public RateLimiter(int rate, int maxDelay, TimeUnit unit) {
      		this.interval = unit.toMillis(1) / rate;
      		this.maxDelay = unit.toMillis(maxDelay);
      	}
      
      	public void delayIfNecessary() throws InterruptedException {
      		long timeToWait = 0L;
      		while (timeToWait == 0L) {
      			long now = System.currentTimeMillis();
      			long next = this.nextRelease.getAndAdd(this.interval);
      			if (next < now) {
      				if (this.nextRelease.compareAndSet(next + this.interval, now + this.interval)) {
      					logger.info("Sleeping for 0");
      					return;
      				}
      				else {
      					logger.info("nextRelease has been changed by another thread");
      				}
      			}
      			else {
      				timeToWait = next - now;
      			}
      		}
      		if (timeToWait > this.maxDelay) {
      			throw new IllegalStateException("Rate limiter maxDelay exceeded");
      		}
      		logger.info("Sleeping for " + timeToWait);
      		Thread.sleep(timeToWait);
      	}
      
      	public static void main(String[] args) throws Exception {
      		RateLimiter rl = new RateLimiter(2, 5, TimeUnit.SECONDS);
      		ExecutorService exec = Executors.newCachedThreadPool();
      		for (int i = 0; i < 15; i++) {
      			final int j = i;
      			exec.execute(() -> {
      				StopWatch watch = new StopWatch("task" + j);
      				watch.start();
      				try {
      					rl.delayIfNecessary();
      				}
      				catch (IllegalStateException | InterruptedException e) {
      					logger.info("delay too long for task" + j);
      				}
      				watch.stop();
      				logger.info(watch.prettyPrint());
      			});
      		}
      		exec.shutdown();
      		exec.awaitTermination(60, TimeUnit.SECONDS);
      	}
      
      }
      
      2018-07-01 14:19:51,697  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-5] : Sleeping for 500
      2018-07-01 14:19:51,705  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-7] : Sleeping for 2499
      2018-07-01 14:19:51,705  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-1] : nextRelease has been changed by another thread
      2018-07-01 14:19:51,699  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-4] : Sleeping for 1499
      2018-07-01 14:19:51,703  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-11] : Sleeping for 4497
      2018-07-01 14:19:51,707  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-9] : Sleeping for 3497
      2018-07-01 14:19:51,703  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-6] : Sleeping for 1999
      2018-07-01 14:19:51,697  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-15] : delay too long for task14
      2018-07-01 14:19:51,707  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-1] : delay too long for task0
      2018-07-01 14:19:51,697  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-8] : Sleeping for 2998
      2018-07-01 14:19:51,702  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-10] : Sleeping for 3997
      2018-07-01 14:19:51,699  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-3] : Sleeping for 999
      2018-07-01 14:19:51,699  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-14] : delay too long for task13
      2018-07-01 14:19:51,699  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-13] : delay too long for task12
      2018-07-01 14:19:51,698  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-2] : Sleeping for 0
      2018-07-01 14:19:51,700  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-12] : Sleeping for 4997
      2018-07-01 14:19:51,710  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-15] : StopWatch 'task14': running time (millis) = 16
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00016  100%  
      
      2018-07-01 14:19:51,710  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-14] : StopWatch 'task13': running time (millis) = 17
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00017  100%  
      
      2018-07-01 14:19:51,710  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-1] : StopWatch 'task0': running time (millis) = 20
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00020  100%  
      
      2018-07-01 14:19:51,710  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-2] : StopWatch 'task1': running time (millis) = 21
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00021  100%  
      
      2018-07-01 14:19:51,711  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-13] : StopWatch 'task12': running time (millis) = 17
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00017  100%  
      
      2018-07-01 14:19:52,208  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-5] : StopWatch 'task4': running time (millis) = 521
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      00521  100%  
      
      2018-07-01 14:19:52,713  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-3] : StopWatch 'task2': running time (millis) = 1024
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      01024  100%  
      
      2018-07-01 14:19:53,209  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-4] : StopWatch 'task3': running time (millis) = 1520
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      01520  100%  
      
      2018-07-01 14:19:53,712  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-6] : StopWatch 'task5': running time (millis) = 2023
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      02023  100%  
      
      2018-07-01 14:19:54,211  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-7] : StopWatch 'task6': running time (millis) = 2522
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      02522  100%  
      
      2018-07-01 14:19:54,711  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-8] : StopWatch 'task7': running time (millis) = 3022
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      03022  100%  
      
      2018-07-01 14:19:55,210  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-9] : StopWatch 'task8': running time (millis) = 3519
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      03519  100%  
      
      2018-07-01 14:19:55,710  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-10] : StopWatch 'task9': running time (millis) = 4020
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      04020  100%  
      
      2018-07-01 14:19:56,208  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-11] : StopWatch 'task10': running time (millis) = 4518
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      04518  100%  
      
      2018-07-01 14:19:56,711  INFO org.springframework.integration.support.RateLimiter [pool-2-thread-12] : StopWatch 'task11': running time (millis) = 5020
      -----------------------------------------
      ms     %     Task name
      -----------------------------------------
      05020  100%  
      
      

        Attachments

          Activity

            People

            • Assignee:
              abilan Artem Bilan
              Reporter:
              grussell Gary Russell
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: