Caching
The Immersive application uses Redis for caching in production, and Memcached in development.
Migration note: production previously used Memcached Cloud (a Heroku add-on). The switch to Redis is part of the move off Heroku to Kamal/Hetzner — see issue #288. It reuses the same Redis instance Sidekiq already depends on (see
docs/technical/production/kamal.md), removing a separate caching service entirely. Development still uses local Memcached for now — that’s an independent, un-migrated convenience setup, not tied to the Heroku move.
Overview
Production caches frequently accessed data (fragment caches, verb pages, etc.) in Redis to reduce database load and improve response times.
Configuration
Production
Configured in config/environments/production.rb, sharing the Redis accessory used by Sidekiq
(see config/initializers/sidekiq.rb) but on a separate logical database index so cache keys
and Sidekiq’s queue data never collide:
- DB 0 — Sidekiq queues
- DB 1 — Rails cache store
config.cache_store = :redis_cache_store, {
url: "redis://#{ENV.fetch("REDIS_URL_HOST")}:#{ENV.fetch("REDIS_URL_PORT")}/1",
namespace: Rails.env,
expires_in: 1.day
}
REDIS_URL_HOST/REDIS_URL_PORT point at the redis Kamal accessory (immersive-redis:6379 —
see config/deploy.yml).
Development
Development uses a local Memcached instance running on localhost:11211. Ensure Memcached is installed and running:
# Install with Homebrew (macOS)
brew install memcached
# Start the service
brew services start memcached
The cache store is configured in config/environments/development.rb:
config.cache_store = :mem_cache_store, "localhost:11211", {
namespace: Rails.env,
expires_in: 1.day,
compress: true
}
Test
The test environment uses :null_store to avoid caching during tests. This ensures:
- Test isolation: No cache state persists between tests
- No external dependencies: Tests don’t require a running Memcached instance
- Predictable behavior: No caching side effects that could affect test results
If you need to test caching behavior specifically, you can temporarily use :memory_store in your test setup, but :null_store is the recommended default for most test scenarios.
Dependencies
Production uses the redis gem (already a dependency for Sidekiq). Development still uses the
dalli gem for local Memcached connectivity.
Cache Features
- Namespace: Each environment uses its own namespace (
Rails.env) to prevent cache collisions - Expiration: Default cache expiration is set to 1 day
- LRU Eviction: Redis’
maxmemory-policy(unset here, defaults to no eviction) governs behavior if the instance runs out of memory — not a practical concern at current traffic and data volumes, but worth revisiting if usage grows
Usage
Rails provides several methods for caching:
# Cache a value
Rails.cache.write("key", "value")
Rails.cache.write("key", "value", expires_in: 1.hour)
# Read a cached value
Rails.cache.read("key")
# Check if a key exists
Rails.cache.exist?("key")
# Delete a cached value
Rails.cache.delete("key")
# Clear the entire cache
Rails.cache.clear
# Fetch with block (caches if not present)
Rails.cache.fetch("key") do
expensive_operation
end
Fragment Caching
Fragment caching is enabled in production. Use it in views:
<% cache @resource do %>
<%= render @resource %>
<% end %>
Troubleshooting
Development: Connection Refused
If you see connection errors, ensure Memcached is running:
brew services start memcached
Production: Cache Not Working
- Confirm the
redisaccessory is running:bin/kamal accessory logs redis - Confirm
REDIS_URL_HOST/REDIS_URL_PORTare set for the app containers:bin/kamal app exec --reuse "env | grep REDIS" - Test from the Rails console:
bin/kamal app exec --reuse "bin/rails console" # Then in console: Rails.cache.write("test", "value") Rails.cache.read("test")
History
- Originally used Solid Cache (database-backed)
- Switched to Memcached Cloud when the app moved to Heroku
- Switched to Redis (
:redis_cache_store) in production as part of the Heroku → Kamal/Hetzner migration (issue #288); development kept Memcached since it isn’t part of that migration
References
- Rails Caching Guide
- Redis Cache Store Documentation
- Dalli Gem Documentation (development only)