CI/CD for a Rails API + Sidekiq with GitHub Actions
Lint, scan, and test your Rails API and Sidekiq jobs on every push.
A Rails API offloads background work to Sidekiq backed by Redis, with Postgres for data. This recipe lints, runs the test suite against both services, scans for security issues, and builds a container.
What the pipeline does
- install gems with bundler (cached)
- lint with rubocop
- prepare the DB and run tests against Postgres + Redis
- scan with brakeman
- build a container image
The workflow
Postgres and Redis service containers back the test run; ruby/setup-ruby with bundler-cache restores gems. Brakeman gates known Rails security issues.
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: postgres
ports: ['5432:5432']
options: >-
--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis:7
ports: ['6379:6379']
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
REDIS_URL: redis://localhost:6379/0
RAILS_ENV: test
steps:
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- run: bundle exec rubocop
- run: bin/rails db:prepare
- run: bundle exec rspec
- run: bundle exec brakeman -qCaching and speed
bundler-cache: true caches gems keyed on Gemfile.lock. The two service containers and the test suite dominate CI time; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) keep frequent runs affordable and auto-retry transient service-startup races.
Deploying
Build a container that runs both Puma (web) and a Sidekiq process (as separate services), push to GHCR or ECR, and run db:migrate as a release step. Deploy web and Sidekiq pointing at the same Postgres and Redis.
Key takeaways
- Back the suite with Postgres and Redis service containers.
- Brakeman gates common Rails security issues in CI.
- Run Puma and Sidekiq as separate deployed processes.