CodexBloom - Programming Q&A Platform

How to handle rate limiting in a scalable Ruby on Rails API with Redis?

👀 Views: 1 💬 Answers: 1 📅 Created: 2025-06-07
ruby-on-rails redis scalability Ruby

I'm integrating two systems and I'm trying to configure I'm not sure how to approach I'm relatively new to this, so bear with me....... I'm stuck on something that should probably be simple. I'm currently building a RESTful API using Ruby on Rails (5.2) and I need to implement rate limiting to prevent abuse, but I want to ensure that it's also scalable as my user base grows. I've decided to use Redis as the store for tracking requests per user. However, I've run into a couple of challenges. Here's a simplified version of my approach: 1. I set up a Redis instance and installed the `redis` gem. My `Gemfile` includes: ```ruby gem 'redis' ``` 2. I created a service object to handle the rate limiting logic. The method checks how many requests a user has made in the last minute: ```ruby class RateLimiter def initialize(user_id) @user_id = user_id @redis = Redis.new end def allowed? current_time = Time.now.to_i key = "rate_limit:#{@user_id}" request_count = @redis.get(key).to_i if request_count < 100 @redis.multi do @redis.incr(key) @redis.expire(key, 60) end true else false end end end ``` 3. In my controller, I invoke this service: ```ruby class Api::V1::MyController < ApplicationController before_action :check_rate_limit def check_rate_limit limiter = RateLimiter.new(current_user.id) render json: { error: 'Rate limit exceeded' }, status: 429 unless limiter.allowed? end end ``` However, I'm seeing some unexpected behavior. In a load test with 100 concurrent users, I noticed that some users were getting a `429 Rate limit exceeded` response even though they shouldn’t have hit the limit yet. When I checked the Redis keys, it looks like multiple increments were being counted for a single user due to race conditions. I've considered using Redis transactions or Lua scripts to ensure atomicity, but I'm not sure how to implement that correctly in this context. What would be the best way to handle this scenario to make sure that the rate limiting is both accurate and scalable? Any advice or code examples would be greatly appreciated! Any examples would be super helpful. I'm working on a application that needs to handle this. What are your experiences with this? For context: I'm using Ruby on Linux. What's the best practice here? I'm working in a Windows 11 environment. What am I doing wrong?