views:

94

answers:

4

I'm creating an API for my Rails app, and I want to track how many times a user calls a particular API method, and cap them say at like 1,000 requests per day. I'm expecting very high request volumes across multiple users.

Do you have a suggestion as to how I can keep track of something like that per user? I want to avoid having to write to the database repeatedly and deal with locks.

I'm okay doing a delayed write (API limit don't have to be super exact), but is there a standard way of doing this?

A: 

It really depends on the # of servers, the dataset, the # of users, etc.

One approach would be to maintain a quota datastructure in memory on the server and update it per invocation. If you have multiple servers you could maintain a memcache of the quota. Obviously, a memory-based implementation wouldn't survive a reboot or restart, so some sort of serializiation would be required to support that.

If quota accuracy is critical it's probably best to just do it in the DB. You could do it in a file, but then you face the same issues you're trying to avoid /w the database.

EDIT: You could also do a mixed approach -- maintain a memory-based cache of user|api|invocation counts and periodically write them to the database.

A bit more info on the requirements would help pare down the options..

DarkSquid
Well, for the time being it's one server. I'm doing image processing (http://www.punypng.com) and am creating an API for it. I expect many users to use punypng to compress whole directories of images (100+ small images).I guess my question is there a plugin or the "Rails-way" of doing this. Memcache isn't an option for me, so having a quota data structure in memory sounds like global variables to me :(
chuboy
Why is memcache not an option for you?
railsninja
No memcached because currently, I'm running this on a shared server (site5) off my own dime.
chuboy
A: 

You could try Apigee. It looks like it's "free up to 10,000 messages per hour".

Disclaimer: I have never used Apigee.

anthony
A: 

Here's a way of doing it using the rails cache

call_count_key = "api_calls_#{params[:api_key]}_#{Time.now.strftime('%Y-%m-%d-%Hh')}"
call_count = Rails.cache.read(call_count_key) || 0
call_count += 1
Rails.cache.write call_count_key, call_count

# here is our limit
raise "too many calls" if call_count > 100

This isn't a perfect solution as it doesn't handle concurrency properly and if you're using the in memory cache (rails' default) then this will be a per process counter

joho
A: 

If you're ok with a hosted solution, take a look at my company, WebServius ( http://www.webservius.com ) that does API management (issuing keys, enforcing quotas, etc). We also have a billing support, so that you will be able to set per-call prices, etc.

Eugene Osovetsky