class TimedRateLimiter; # not completely reliable if called from multiple threads # rate is unit per second def initialize rate, max, credit; @rate, @max = rate, max; 0 < rate or fail "invalid rate for TimedRateLimiter"; 0 < max or fail "invalid max for TimedRateLimiter"; @time = Time.now; @tally = if credit < 0; 0 else credit end; @lock = Mutex.new; end; def update; time = Time.now; @tally += (time - @time) * @rate; if @max < @tally; @tally = @max; end; @time = time; end; def consume amt = 1; slp = (); @lock.synchronize do 0 <= amt or amt = 0; update; if @tally < amt; slp = Float(amt - @tally) / @rate; end; end; if slp sleep slp; end; @lock.synchronize do @tally -= amt; end; true; end; def try_consume amt = 1; r = false; @lock.synchronize do 0 <= amt or amt = 0; update; if amt <= @tally; @tally -= amt; r = true; end; end; r; end; end; #### @request_limiter = TimedRateLimiter.new 3, 3, 1; #### @request_limiter.consume;