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;