Rate limiting

Rack::Attack (#382), configured in config/initializers/rack_attack.rb. Counters live in Rails.cache (Redis in production, memcached in dev). If the cache store is down, both stores’ error handling makes throttling fail open — requests succeed uncounted; nothing 500s.

Throttle Key Limit
logins/ip IP 10/min on POST /users/sign_in
logins/email submitted email 20/hour on POST /users/sign_in
signups/ip IP 10/hour on POST /users
password_resets/ip IP 5/hour on POST /users/password
contacts/ip IP 5/hour on POST /contacts
audio/user user id (IP when signed out) 30/min on POST /api/resources/audio — every uncached hit is a paid Polly call

Safelists: /up (Kamal health checks) and /admin + /sidekiq.

Throttled requests get a plain-text 429 with a Retry-After header. Every throttle hit logs a [Rack::Attack] warning with the matched rule, IP, and path.

Rack::Attack is disabled in the test environment (the suite posts to auth endpoints freely); test/integration/rack_attack_test.rb enables it with a MemoryStore per test.


This site uses Just the Docs, a documentation theme for Jekyll.