There is a hypothetical web server which supports only one very simple API - count of requests received in the last hour, minute and second. This server is very popular in t
My solution :
Maintain a hash of 3600 ,which contains a count,timestamp as fields.
For each request for:
Case(1) : if i/p timestamp==hash[idx].timestamp,hash[count]++;
Case(2) : if i/p timestamp>hash[idx].timestamp,then hash[idx].count=1 and hash[idx].timestamp=inputTimeStamp
Case(3): : if i/p timestamp<hash[idx].count // old request, can be ignored.
Now for any query for last second,minute,hour: Find idx as above, and as long as the timestamp matches with in given second/range/minute,keep on iterating back from from idx in circular manner.
Why not just use a circular array? We have 3600 elements in that array.
index = 0;
Array[index % 3600] = count_in_one_second.
++index;
if you want last second, return the last element of this array. if you want last minute, return the sum of last 60 elements. if you want last hour, return the sum of the whole array (3600 elements).
Isn't his a simple and effective solution?
Thanks
Deryk
I had to solve this problem in Go, and I don't think I saw this approach yet, but it may also be very specific to my use case.
Since it is connecting to a 3rd party API and needs to limit its own requests, I simply kept a counter for the last second and a counter for the last 2 minutes (the two counters I needed)
var callsSinceLastSecond, callsSinceLast2Minutes uint64
Then I'd launch my requests in separate go routines when the calls counters were below my allowable limit
for callsSinceLastSecond > 20 || callsSinceLast2Minutes > 100 {
time.Sleep(10 * time.Millisecond)
}
And at the end of each go routine I would atomically decrement the counter.
go func() {
time.Sleep(1 * time.Second)
atomic.AddUint64(&callsSinceLastSecond, ^uint64(0))
}()
go func() {
time.Sleep(2 * time.Minute)
atomic.AddUint64(&callsSinceLast2Minutes, ^uint64(0))
}()
And that seems to work so far without any issue with some pretty heavy testing so far.
What about a simple list of timestamps? Each time you're making a request you append the current timestamp to the list. And each time you want to check if you're under the rate limit, you first remove timestamps older than 1 hour to prevent stack overflow (hehe) then you count the number of timestamps in the last second, minute, whatever.
It could be done easily in Python:
import time
requestsTimestamps = []
def add_request():
requestsTimestamps.append(time.time())
def requestsCount(delayInSeconds):
requestsTimestamps = [t for t in requestsTimestamps if t >= time.time() - 3600]
return len([t for t in requestsTimestamps if t >= time.time() - delayInSeconds])
I guess this can be optimized but you see the idea.