Agent skill
async-falcon-rails
Transform a Rails application to use Falcon web server with async job processing (async-job), async Action Cable, and Redis-compatible database (Valkey for production). Use when the user wants to add async/Falcon stack to a Rails project, migrate from Puma to Falcon, or set up async job processing with Redis for both development and production environments including Kamal deployment.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/async-falcon-rails
SKILL.md
Async Falcon Rails
Overview
Transform a Rails application to use the Falcon web server with async job processing, async Action Cable, and Redis-compatible database (Valkey for production). This skill handles the complete migration from Puma to Falcon, configures async job adapters, sets up Redis/Valkey for Action Cable and job queues, and configures Kamal deployment for production.
When to Use
Use this skill when the user:
- Wants to add async/Falcon stack to an existing Rails project
- Needs to migrate from Puma to Falcon web server
- Requests async job processing setup with Redis
- Wants to configure async Action Cable
- Needs Kamal deployment configuration for the async stack
Prerequisites
Before applying this skill, verify:
- The project is a Rails application (check for
Gemfile,config/application.rb) - The project structure includes
config/environments/directory - Bundle is available (
bundlecommand works) - If Kamal deployment is needed, check for
config/deploy.yml
Workflow
Follow these steps in order to transform a Rails application to use the async/Falcon stack:
Step 1: Update Gemfile Dependencies
Replace Puma with Falcon and add async dependencies:
bundle remove puma
bundle add falcon
bundle add async-job-processor-redis
bundle add async-job-adapter-active_job
bundle add async-cable
bundle add redis
After running these commands, verify the Gemfile includes:
gem "falcon"gem "async-job-processor-redis"gem "async-job-adapter-active_job"gem "async-cable"gem "redis"(providesAsync::Redis::Endpointfor endpoint parsing)
Step 2: Update Dockerfile for SSL Dependencies
CRITICAL: The async/Falcon stack requires OpenSSL development libraries to build properly. Without this, Docker builds will fail.
Edit the Dockerfile and add libssl-dev to the system dependencies.
Find the line that installs build packages (usually around line 40):
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
Update it to include libssl-dev:
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev libssl-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
Why this is needed: The Falcon web server and async gems depend on native extensions that require OpenSSL headers to compile. Without libssl-dev, the Docker build will fail with compilation errors.
Step 3: Create Async Job Configuration
Create config/initializers/async_job.rb with the following content:
require "async/job"
require "async/job/processor/aggregate"
require "async/job/processor/redis"
require "async/job/processor/inline"
require "async/redis/endpoint"
Rails.application.configure do
# Resolve Redis endpoint from REDIS_URL; fallback to localhost for dev/test.
redis_endpoint = Async::Redis::Endpoint.parse(
ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" }
)
config.async_job.define_queue "default" do
enqueue Async::Job::Processor::Aggregate
# Ensure the job runner connects to the accessory container (or localhost in dev).
dequeue Async::Job::Processor::Redis, endpoint: redis_endpoint
end
config.async_job.define_queue "local" do
dequeue Async::Job::Processor::Inline
end
end
This configuration:
- Sets up a "default" queue using Redis for job processing
- Parses the REDIS_URL environment variable to create a proper Redis endpoint
- Passes the endpoint to the Redis processor for both development and production
- Sets up a "local" queue for inline processing
- Uses Aggregate processor for enqueuing and Redis for dequeuing
Step 4: Update Procfile for Development
Update Procfile.dev to include the async job processor:
Add this line to the existing Procfile.dev:
jobs: bundle exec async-job-adapter-active_job-server
The complete Procfile.dev should include at minimum:
web: bin/rails s
jobs: bundle exec async-job-adapter-active_job-server
If the project uses Vite or other frontend build tools, keep those lines as well.
Step 5: Configure Development Environment
Edit config/environments/development.rb to use async_job queue adapter.
Find the section about ActiveJob (usually near config.active_job.verbose_enqueue_logs) and add:
config.active_job.queue_adapter = :async_job
Step 6: Configure Production Environment
Edit config/environments/production.rb to configure both async_job and Redis cache:
Find and update or add these configurations:
# For cache store (usually around line 50)
config.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"] }
# For queue adapter (usually around line 53)
config.active_job.queue_adapter = :async_job
Step 7: Configure Application for Async/Cable
Edit config/application.rb to add async/cable support:
- At the top of the file, after
require "rails/all", add:
require "async/cable"
- Inside the
class Application < Rails::Applicationblock, afterconfig.load_defaults, add:
# Configure async/fiber support
config.active_record.permanent_connection_checkout = :disallowed
config.active_support.isolation_level = :fiber
These settings enable fiber-based isolation for async operations.
Step 8: Generate Action Cable Base Channel
Run the Rails generator to create the base Action Cable structure:
bin/rails generate channel BaseChannel
This creates:
app/channels/application_cable/channel.rbapp/channels/application_cable/connection.rbapp/channels/base_channel.rbtest/channels/base_channel_test.rb
Step 9: Mount Action Cable in Routes
Edit config/routes.rb to mount the Action Cable server.
Add this line at the top of the Rails.application.routes.draw block:
mount ActionCable.server => '/cable'
Step 10: Configure Cable to Use Redis
Edit config/cable.yml to use Redis for all environments:
Update the configuration to:
development:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: PROJECT_NAME_production
test:
adapter: test
production:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: PROJECT_NAME_production
Replace PROJECT_NAME with the actual Rails application name (found in config/application.rb as the module name).
Step 11: Configure Kamal Deployment (If Applicable)
If the project uses Kamal for deployment (check for config/deploy.yml), update the deployment configuration:
11.1: Add Job Server
In the servers: section, add or uncomment the job server configuration:
servers:
web:
- 192.168.0.1
job:
hosts:
- 192.168.0.1
cmd: bundle exec async-job-adapter-active_job-server
options:
init: true
Key configuration:
init: true: Skips health checks for the job server (avoids 30-second deployment wait)- Job servers don't expose HTTP endpoints, so health checks would timeout unnecessarily
11.2: Configure Redis/Valkey Accessory
In the accessories: section (create if it doesn't exist), add Redis/Valkey configuration:
accessories:
redis:
image: valkey/valkey:9
host: 192.168.0.1
port: "127.0.0.1:6379:6379"
directories:
- redis_data:/data
Key considerations:
- Important: Use Valkey instead of Redis due to Redis licensing changes. Valkey is a Redis-compatible fork maintained by the Linux Foundation
- Use Valkey 9 or latest stable version
- Port binding
"127.0.0.1:6379:6379"prevents public exposure (localhost only) - Volume name
redis_dataprevents conflicts with other services (e.g., PostgreSQL)
11.3: Add REDIS_URL Environment Variable
In the env: section under clear:, add:
env:
clear:
REDIS_URL: redis://PROJECT_NAME-redis:6379/1
Replace PROJECT_NAME with the service name from the top of deploy.yml. The format follows Kamal's Docker naming convention: {service_name}-{accessory_name}.
11.4: Configure Multi-Architecture Builds
Update the builder: section to support multiple architectures:
builder:
arch:
- amd64
- arm64
This enables building Docker images for:
- amd64: Intel/AMD processors (Windows, Linux, older Macs)
- arm64: Apple Silicon (M1/M2/M3 Macs), ARM-based Linux servers
Verification Steps
After completing the workflow, verify the setup:
- Gemfile: Check that Puma is removed and all async gems are added
- Dockerfile: Verify
libssl-devis included in the apt-get install line - Initializers: Verify
config/initializers/async_job.rbexists and includes endpoint configuration (endpoint: redis_endpoint) - Environments: Confirm
async_jobqueue adapter in development.rb and production.rb - Application: Verify
async/cablerequire and fiber isolation config in application.rb - Cable: Check that Action Cable is mounted in routes.rb
- Cable Config: Confirm cable.yml uses Redis for development and production
- Kamal (if applicable): Verify job server with
init: true, Redis accessory, REDIS_URL, and multi-arch build config in deploy.yml
Important Notes
Redis/Valkey Dependency
This stack requires Redis-compatible database to be running:
- Development: Start Redis locally with
redis-serveror use Docker - Production: Valkey (Redis-compatible) is deployed as a Kamal accessory (configured in deploy.yml)
- Note: We use Valkey instead of Redis in production due to Redis licensing changes. Valkey is a fully Redis-compatible fork maintained by the Linux Foundation
Environment Variables
The REDIS_URL environment variable must be set:
- Development: Defaults to
redis://localhost:6379/1(configured in cable.yml) - Production: Set via Kamal deploy.yml or environment configuration
Kamal Naming Conventions
When using Kamal:
- Redis accessory will be named:
{service_name}-redis - Use this name in REDIS_URL:
redis://{service_name}-redis:6379/1 - Volume names should be descriptive:
redis_data,postgres_data, etc.
Port Binding Security
The Redis port binding "127.0.0.1:6379:6379" ensures:
- Redis is accessible to containers on the same Docker network
- Redis is NOT exposed to the public internet
- Only localhost connections are allowed on the host
Troubleshooting
Docker Build Errors
If Docker build fails with compilation errors about OpenSSL or missing headers:
- Symptom: Build fails during gem installation with errors like "openssl/ssl.h: No such file or directory"
- Cause: Missing
libssl-devsystem dependency in Dockerfile - Solution: Add
libssl-devto the apt-get install line in Dockerfile (see Step 2) - Verification: Check that the Dockerfile includes
libssl-devin the package list alongsidebuild-essential,git,libyaml-dev, andpkg-config
This is a critical dependency for Falcon and async gems - without it, the Docker image cannot be built.
Bundle Errors
If bundle add commands fail:
- Check that Gemfile is not locked with version conflicts
- Try
bundle updateto resolve dependency issues - Verify network connectivity to rubygems.org
Redis Connection Errors
If the application cannot connect to Redis:
- Development: Ensure Redis is running locally (
redis-cli pingshould returnPONG) - Production: Check that REDIS_URL environment variable is set correctly
- Verify cable.yml configuration matches the REDIS_URL format
Kamal Deployment Issues
If Kamal deployment fails:
- Verify all placeholders (PROJECT_NAME, IP addresses) are replaced with actual values
- Check that Redis accessory is running:
kamal accessory details redis - Ensure REDIS_URL matches the Kamal service naming convention
Deployment Timeouts
If Kamal deployment hangs for 30 seconds when deploying the job server:
- Symptom: Deployment waits and then shows "Container not ready" for job server
- Cause: Job server doesn't expose HTTP endpoints, so health checks timeout
- Solution: Add
options:withinit: trueto the job server configuration in deploy.yml (see Step 11.1) - Why it works:
init: truetells Kamal to skip health checks for this service
References
For detailed configuration templates and examples, see:
references/configuration-templates.md- Complete file templates and patterns
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?