Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveSupport::Cache::MemCacheStore unsupported #50

Closed
owentran opened this issue Oct 1, 2019 · 5 comments
Closed

ActiveSupport::Cache::MemCacheStore unsupported #50

owentran opened this issue Oct 1, 2019 · 5 comments

Comments

@owentran
Copy link

owentran commented Oct 1, 2019

Hi.

We recently upgraded from the dalli gem to mem_cache_store. This silently broke the rack-throttle gem since it expects the cache to support :has_key?, :get, and :set.

To fix it, we applied this monkey patch...

  class RackThrottleMemCacheStore < ActiveSupport::Cache::MemCacheStore
    alias_method :has_key?, :exist?
    alias_method :get, :read
    alias_method :set, :write
  end

  # Limits :max requests per minute by session id
  cache_servers   = Rails.application.config.cache_store[1...-1]
  cache_options   = Rails.application.config.cache_store.last
  memcache_store  = RackThrottleMemCacheStore.new(cache_servers, cache_options)

  Rails.application.config.middleware.use Rack::Throttle::Minute,
                                          max:        60,
                                          key_prefix: :throttle,
                                          cache:      memcache_store

I'm not sure if there's a better way but sharing this tidbit for others who may be running this with dalli and then switched to mem_cache_store.

Thanks for this gem!
Owen

@FreekingDean
Copy link
Collaborator

Hi Owen! Most people are using rack-throttle for legacy versions of ruby, but if you are able to: https://github.com/kickstarter/rack-attack is much more feature full & maintained!

@owentran
Copy link
Author

owentran commented Oct 2, 2019

Thanks FreekingDean. I'll work on migrating with our next sprint and add any gotchas/comments to this issue.

@FreekingDean
Copy link
Collaborator

Would love to know if there are large sweeping differences, but I believe it was originally based on this repo.

@owentran
Copy link
Author

owentran commented Oct 8, 2019

The switch took about an hour.

  • safelist took care of the IP whitelisting
  • Created a Rack::Attack::Request like the example config to whitelist localhost IP and a few paths
  • Able to create three different throttles based on different paths
  • Plugs right into Rails.cache.store without any issues

The hardest part was understanding how to log if something was throttled. Here was my solution...

ActiveSupport::Notifications.subscribe("throttle.rack_attack") do |_name, _start, _finish, _request_id, payload|
  request = payload[:request]
  Rails.logger.error("[rack-attack] throttle=#{request.env["rack.attack.matched"]}, path=#{request.path}, ip=#{request.ip}")
end

Will throw it into production in two weeks and see how it performs.

@owentran
Copy link
Author

Works great. Only issue was that the IP method needs to be overwritten if you deal with HTTP_X_FORWARDED_FOR otherwise you'll block all traffic from your load balancers.

  def ip
    if addr = env['HTTP_X_FORWARDED_FOR']
      (addr.split(',').first || env['REMOTE_ADDR']).to_s.strip
    else
      env['REMOTE_ADDR']
    end
  end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants