Open
Description
Rack Attack is written so it doesn't fail if Redis is down on application startup. That's cool.
However, it will bring down the application if Redis server starts misbehaving at later point, for example:
Redis::CommandError: OOM command not allowed when used memory > 'maxmemory'
Preferably, we should ignore any Redis errors and pass the request to the next middleware.
Alternatively, we should allow users to define an exception handler for any errors that happen inside Rack Attack (not the next middleware), with an option to bypass the exception and continue processing. Example:
Rack::Attack.exception_handler = lambda do |exception|
Rails.logger.error exception # do whatever you want here
raise # Re-raises the exception, therefore failing the request. Without an explicit `raise` in the handler, the processing would continue
end
Here's the full stacktrace from when the problem happened and killed my application:
lib/redis/client.rb:121 call
lib/redis.rb:769 block in setex
lib/redis.rb:58 block in synchronize
/home/ec2-user/.rbenv/versions/2.6.3/lib/ruby/2.6.0/monitor.rb:230 mon_synchronize
lib/redis.rb:58 synchronize
lib/redis.rb:768 setex
redis-store (1.6.0) lib/redis/store/interface.rb:17 setex
redis-store (1.6.0) lib/redis/store/serialization.rb:13 block in setex
redis-store (1.6.0) lib/redis/store/serialization.rb:40 _marshal
redis-store (1.6.0) lib/redis/store/serialization.rb:13 setex
redis-store (1.6.0) lib/redis/store/namespace.rb:11 block in setex
redis-store (1.6.0) lib/redis/store/namespace.rb:89 namespace
redis-store (1.6.0) lib/redis/store/namespace.rb:11 setex
redis-store (1.6.0) lib/redis/store/ttl.rb:6 set
redis-store (1.6.0) lib/redis/store/serialization.rb:5 block in set
redis-store (1.6.0) lib/redis/store/serialization.rb:40 _marshal
redis-store (1.6.0) lib/redis/store/serialization.rb:5 set
redis-store (1.6.0) lib/redis/store/namespace.rb:7 block in set
redis-store (1.6.0) lib/redis/store/namespace.rb:89 namespace
redis-store (1.6.0) lib/redis/store/namespace.rb:7 set
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:282 block (2 levels) in write_entry
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:270 with
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:282 block in write_entry
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:340 failsafe
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:280 write_entry
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:86 block in write
lib/active_support/cache.rb:547 block in instrument
lib/appsignal/hooks/active_support_notifications.rb:21 block in instrument
lib/active_support/notifications/instrumenter.rb:20 instrument
lib/appsignal/hooks/active_support_notifications.rb:35 instrument
lib/appsignal/hooks/active_support_notifications.rb:20 instrument
lib/active_support/cache.rb:547 instrument
redis-activesupport (5.2.0) lib/active_support/cache/redis_store.rb:81 write
/home/ec2-user/.rbenv/versions/2.6.3/lib/ruby/2.6.0/delegate.rb:83 method_missing
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb:34 write
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb:21 increment
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/cache.rb:74 do_count
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/cache.rb:27 count
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/throttle.rb:31 matched_by?
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/configuration.rb:93 block in throttled?
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/configuration.rb:92 any?
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack/configuration.rb:92 throttled?
/var/www/apps/app/shared/bundle/ruby/2.6.0/bundler/gems/rack-attack-6d1bc9b617c5/lib/rack/attack.rb:118 call
(... other middlewares ...)