Skip to content

Instantly share code, notes, and snippets.

@glebm
Created October 24, 2012 15:57
Show Gist options
  • Save glebm/3946921 to your computer and use it in GitHub Desktop.
Save glebm/3946921 to your computer and use it in GitHub Desktop.
Example Rainbows Config
# -*- encoding : utf-8 -*-
#= Rainbows HTTP server (on unix socket!)
#== Rainbows can be used to manage multiple forked workers in a specified concurrency-IO model
# Set working directory for Capistrano
# pwd -L keeps symlinks
working_directory `pwd -L`.chomp
# Listen through a unix socket
# This is awesome because no external ports are opened
# Unix sockets are always local, which means individual workers cannot be targeted from the outside (more DoS proof)
# Put in pids, because pids is symlinked to shared
listen File.expand_path("tmp/pids/server.sock"), backlog: 64
pid "tmp/pids/server.pid"
# Log files for the master process
stderr_path "log/server.stderr.log"
stdout_path "log/server.stdout.log"
# Preload master to spawn (fork) workers faster
# Not that this won't do much in development, because classes are not pre-loaded
preload_app true
# Enable copy on write friendly GC for rubies that have it as an option (2.0.0dev etc)
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true
before_fork do |server, worker|
# Kill non-threadsafe connections before fork
ActiveRecord::Base.connection.disconnect!
# Redis calls are thread-safe, but synchronized (can be used only by 1 thread at a time).
# Disconnect to give each thread its own redis connection
Redis.current.client.disconnect
# Dalli (memcached gem) does not need anything special, it will detect and gracefully reopen shared sockets.
#= Spawn a new worker, kill an old one: zero downtime deployments
#= Make sure to leave enough memory for one extra worker on the server to avoid swapping
# Rainbows signals documentation: http://rainbows.rubyforge.org/SIGNALS.html
# On deploy USR2 gets sent to master
# USR2 doesn't kill the master, but it starts a new one and marks the current one as old
# The old master process will pid file have “.oldbin” appended to the name
old_pid_file = "#{server.config[:pid]}.oldbin"
# if the deployment server fails to start, the application will still be running!
# unless we are in the "old" server and not restarting:
unless server.pid == old_pid_file
begin
new_workers = worker.nr + 1 # a count of new workers spawned so far
# are we spawning the last worker?
# worker_processes is the configured number of total worker
signal = if new_workers >= server.worker_processes
# quit old master
:QUIT
else
# will still spawn more, so old master still has some running
# - decrement old master workers count
:TTOU
end
Process.kill signal, File.read(old_pid_file).to_i # Process.kill(signal, pid) send the signal on unix
rescue Errno::ENOENT, Errno::ESRCH
end
end
# Throttle the master from forking too quickly by sleeping
# This is to work around a unix socket implementation issue
sleep 1
end
after_fork do |server, worker|
# Connect to non tread-safe resources
ActiveRecord::Base.establish_connection
Redis.current = Redis.new
# Dalli (memcached gem) does not need anything special, it will detect and gracefully reopen shared sockets.
end
# Use at least one worker per core
# Memory usage won't increase by much per worker on copy-on-write friendly rubies
worker_processes 4
# Nuke workers after 90 seconds (default is 60)
timeout 90
# Set up rainbows concurrency model
# EventMachine provides us with evented socket IO
#= Warning: This model does not implement streaming “rack.input”.
# If you need Rails streaming support use a different model, e.g. ThreadSpawn
Rainbows! do
use :ThreadPool
worker_connections 100 # connections are super-cheap
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment