Throttling requests to a Ruby on Rails API
Here's some rack middleware that accomplishes what you're after: http://github.com/dambalah/api-throttling
and here's a blog post about the development of that middleware: http://blog.messagepub.com/2009/05/05/how-to-rack-middleware-for-api-throttling/
Throttling outbound API calls generated by a Rails app
The reason nobody talk about outbound throttling is that it's usually pretty trivial, since you control it. Controlling bandwidth can be a bit harder, but controlling number of request ?
ri Kernel#sleep
So, if you're allowed 10 api calls per min you just sleep(6) after each call
Best practice for rate limiting users of a REST API?
This is all done with outer webserver, which listens to the world (i recommend nginx or lighttpd).
Regarding rate limits, nginx is able to limit, i.e. 50 req/minute per each IP, all over get 503 page, which you can customize.
Regarding expected temporary down, in rails world this is done via special maintainance.html page. There is some kind of automation that creates or symlinks that file when rails app servers go down. I'd recommend relying not on file presence, but on actual availability of app server.
But really you are able to start/stop services without losing any connections at all. I.e. you can run separate instance of app server on different UNIX socket/IP port and have balancer (nginx/lighty/haproxy) use that new instance too. Then you shut down old instance and all clients are served with only new one. No connection lost. Of course this scenario is not always possible, depends on type of change you introduced in new version.
haproxy is a balancer-only solution. It can extremely efficiently balance requests to app servers in your farm.
For quite big service you end-up with something like:
- api.domain resolving to round-robin N balancers
- each balancer proxies requests to M webservers for static and P app servers for dynamic content. Oh well your REST API don't have static files, does it?
For quite small service (under 2K rps) all balancing is done inside one-two webservers.
Rate-limiting for rails controllers
Well, finally rack throttle is a good solution.
You can do it the following way. You need to define your custom limiter. It can be based on either of the following limiters
Rack::Throttle::Limiter
Rack::Throttle::Interval
Rack::Throttle::Hourly
Rack::Throttle::Daily
Everything you need to do is derive from one of the above classes to define custom logic. For example:
class CustomLimiter < Rack::Throttle::Interval
def allowed?(request)
#custom logic here
end
end
You should put this file in the RAILS_ROOT/lib
path. Then in the application.rb
file you should specify what class to use as a limiter. For example if you want to apply limiter only to one action you can do it the following way:
#lib/custom_limiter.rb
class CustomLimiter < Rack::Throttle::Interval
def allowed?(request)
path_info = Rails.application.routes.recognize_path request.url rescue {}
if path_info[:controller] == "application" and path_info[:action] == "check_answer"
super
else
true
end
end
end
#config/application.rb
class Application < Rails::Application
...
#Set up rate limiting
config.require "custom_limiter"
config.middleware.use CustomLimiter, :min => 0.2
...
end
You may need to take this into consideration
Hope this will be useful
UPD:
you may want to check out another solution: rack-attack
Related Topics
Uninstall Ruby Version from Rbenv
Rails Flash Message Remains for Two Page Loads
How to Load a Spec_Helper.Rb Automatically in Rspec 2
How to Recompile a Ruby with Rvm
Adding an Instance Variable to a Class in Ruby
Is There a Good Admin Generator for Ruby on Rails
How to Update Gems on Production Server
Using Ruby's Optionparser to Parse Sub-Commands
Why Are Symbols Not Frozen Strings
Accessing Ruby Class Variables with Class_Eval and Instance_Eval
Best Place to Store Model Specific Constants in Rails 3.1
How to Replace Multiple Newlines in a Row with One Newline Using Ruby
Regex with Named Capture Groups Getting All Matches in Ruby
Difference Between Add_Dependency and Add_Runtime_Dependency
What Is the Preferred Way (Better Style) to Name a Namespace in Ruby? Singular or Plural
Rubymine: Rails Server Launcher Wasn't Found in the Project
What Are the Things You Would Like Improved in the Ruby Language