Integrating Grape with Sidekiq for Asynchronous Processing in Rails
When building an API in a Rails application using Grape, there is a natural tendency to handle all logic synchronously. For small applications or internal tools, that can work well. But for a growing SaaS platform or public-facing API, doing too much work in the request cycle leads to slower response times and can make your endpoints fragile.
This post walks through the process of integrating Grape with Sidekiq so that heavy tasks can be moved to background workers. The goal is to keep endpoints fast and resilient while offloading expensive processing.
Why asynchronous processing matters
Many common tasks in an API do not need to be done immediately. Examples include sending confirmation emails, syncing to a third-party service, exporting data, or generating reports. By sending these jobs to a background processor like Sidekiq, the API can respond quickly and let the user continue without waiting.
Separating these tasks also gives better observability and error handling. Sidekiq offers retries, job tracking, and simple ways to inspect queues out of the box.
Setting up Grape and Sidekiq
Assuming you already have a Rails application with Grape installed, the next step is to add Sidekiq and Redis. Redis is used to store the job queue.
Add the following to your Gemfile:
gem 'grape'
gem 'sidekiq'
Run bundle install
and start Redis if it is not already running.
Next, configure Rails to use Sidekiq for background jobs by setting the queue adapter in config/application.rb
:
config.active_job.queue_adapter = :sidekiq
You can also add a basic Sidekiq YAML config file to control queue priorities:
# config/sidekiq.yml
:queues:
- default
Creating a Sidekiq worker
To use Sidekiq directly, create a new file in app/workers
. For example, to send a welcome email:
class WelcomeEmailWorker
include Sidekiq::Worker
def perform(this_username)
user = User.find_by(username: this_username)
UserMailer.welcome(user).deliver_now
end
end
This worker fetches a user and sends an email using a standard Rails mailer. The goal here is to keep logic focused and avoid branching inside the job.
Triggering a background job from a Grape endpoint
Now we connect the worker to a Grape endpoint. Here is an example of an endpoint that creates a user and queues a welcome email to be sent later:
# app/api/v1/users_api.rb
module V1
class UsersAPI < Grape::API
version 'v1', using: :path
format :json
resource :users do
desc 'Create a user and queue welcome email'
params do
requires :email, type: String, desc: 'Users email'
requires :name, type: String, desc: 'Users name'
requires :username, type: String, desc: 'Users username'
end
post do
user = User.create!(declared(params))
# Enqueue welcome email
WelcomeEmailJob.perform_later(user.username)
status 201
{ id: user.id, email: user.email, name: user.name, username: user.username }
end
end
end
end
Once the user is saved to the database, the perform_async
method queues the job to be picked up by a running Sidekiq worker process.
This lets the API return a response right away instead of waiting for the email to be sent. In a production environment, this difference becomes more noticeable when there are many different parts to the request, or many requests to be triggered.
Running Sidekiq
To process jobs, Sidekiq must be running in a separate process from your Rails app server. In development, you can run it with:
bundle exec sidekiq
You should see logs indicating that the worker has started and is listening for jobs on the default queue.
Error handling and retries
Sidekiq includes built-in retry logic. You can configure the number of retries or disable them for specific jobs.
To log errors explicitly or report them to an external service, wrap your job logic in a begin-rescue block:
def perform(this_username)
user = User.find_by(username: this_username)
UserMailer.welcome(user).deliver_now
rescue => e
Rails.logger.error("Welcome email failed: #{e.message}")
raise e
end
Raising the error ensures that Sidekiq still sees the job as failed and can retry it if needed.
Conclusion
Integrating Grape with Sidekiq is a simple but effective way to improve performance and reliability in a Rails API. It lets you keep endpoint logic clean and offload work that does not need to be completed immediately.
This approach scales well for APIs that process uploads, send notifications, or interact with third-party services. It also aligns with the principle of keeping the request-response cycle short and predictable.
If you’re working with Grape in a growing Rails project, this is a natural next step.
Comments