Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Unicorn configuration with master warm up and other daemons as workers support. (See lastest and full version at https://github.com/coletivoEITA/noosfero-cookbook/blob/master/templates/default/unicorn.conf.rb.erb)
RailsRoot = File.expand_path "#{File.dirname __FILE__}/.."
PidsDir = "#{RailsRoot}/tmp/pids"
OldPidFile = "#{PidsDir}/unicorn.pid.oldbin"
ListenAddress = "127.0.0.1"
ListenPort = 50000
UnixListen = "tmp/unicorn.sock"
Backlog = 2048
Workers = 4
Timeout = 20 * 60
WarmUp = true
WarmUpTime = 1
# caution use non cacheable urls
WarmUpUrl = ['/admin/plugins', '/', '/profile/content']
CurrentPrio = Process.getpriority Process::PRIO_PROCESS, 0
# put "* - nice 0" on /etc/security/limits.conf to enable
WarmUpRenice = `bash -c 'ulimit -e'`.to_i-20 >= CurrentPrio rescue false
WarmUpRenicePrio = 19
begin
require 'unicorn/worker_killer'
WorkerKiller = true
rescue LoadError
WorkerKiller = nil
end
WorkerKillByRequests = 500..600
WorkerKillByMemory = 208..256
WorkerListen = true
WorkerPidFile = true
WorkerDaemons = {
0 => {
:name => 'delayed_job',
:run => proc{
Delayed::Worker.before_fork
Delayed::Command.new([]).run 'delayed_job'
},
},
1 => {
:name => 'feed-updater',
:run => proc{
FeedUpdater.new.start
},
},
}
working_directory RailsRoot
worker_processes (if Workers < WorkerDaemons.count+1 then WorkerDaemons.count+1 else Workers end)
timeout Timeout
stderr_path "#{RailsRoot}/log/unicorn.stderr.log"
stdout_path "#{RailsRoot}/log/unicorn.stdout.log"
pid "#{PidsDir}/unicorn.pid"
listen "#{RailsRoot}/#{UnixListen}", :backlog => Backlog
listen "#{ListenAddress}:#{ListenPort}", :tcp_nopush => true
# combine Ruby 2 or REE with "preload_app true" for memory savings
# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
preload_app true
GC.copy_on_write_friendly = true if GC.respond_to? :copy_on_write_friendly=
# this is loaded on first run or restart conditions (URS2, HUP). Unset on first before_fork call
master_run = true
before_fork do |server, worker|
if master_run
if WarmUp
Process.setpriority Process::PRIO_PROCESS, 0, WarmUpRenicePrio if WarmUpRenice
require 'rack/test'
client = Rack::MockRequest.new server.app
Array(WarmUpUrl).each do |url|
client.get url
end
Process.setpriority Process::PRIO_PROCESS, 0, CurrentPrio if WarmUpRenice
end
# Disconnect since the database connection will not carry over
ActiveRecord::Base.connection.disconnect! if defined? ActiveRecord::Base
if File.exists? OldPidFile
Thread.new do
# wait a little for the new master
sleep WarmUpTime
# a .oldbin file exists if unicorn was gracefully restarted with a USR2 signal
# we should terminate the old process now that we're up and running
old_pid = File.read(OldPidFile).to_i
begin
Process.kill "QUIT", old_pid
File.delete OldPidFile
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
master_run = false
end
end
after_fork do |server, worker|
daemon = WorkerDaemons[worker.nr]
# Start up the database connection again in the worker
ActiveRecord::Base.establish_connection if defined? ActiveRecord::Base
# reset memcache connection (if using memcache-client)
Rails.cache.instance_variable_get(:@data).reset if Rails.cache.class.to_s == 'ActiveSupport::Cache::MemCacheStore'
if WorkerKiller
Unicorn::WorkerKiller::MaxRequests.new nil, WorkerKillByRequests.begin, WorkerKillByRequests.end if WorkerKillByRequests
Unicorn::WorkerKiller::Oom.new nil, WorkerKillByMemory.begin * (1024**2), WorkerKillByMemory.end * (1024**2) if WorkerKillByMemory
end unless daemon
# say to the kernel to kill very big workers first than other processes
# Not very secure
#File.open("/proc/#{Process.pid}/oom_adj", "w"){ |f| f << '12' }
if WorkerListen
# per-process listener ports for debugging/admin/migrations
server.listen "#{ListenAddress}:#{ListenPort + worker.nr}", :tries => -1, :delay => 5
end unless daemon
if WorkerPidFile
child_pid_file = server.config[:pid].sub '.pid', ".#{worker.nr}.pid"
system "echo #{Process.pid} > #{child_pid_file}"
end
end
# daemons support
require 'active_support/all'
class Unicorn::HttpServer
def worker_loop_with_daemons worker
daemon = WorkerDaemons[worker.nr]
if daemon
ctx = START_CTX.dup #save for later use with proc_name
init_worker_process worker
START_CTX.merge! ctx
name = "#{worker.nr}:#{daemon[:name]}"
proc_name "worker[#{name}]"
@logger.info "worker=#{name} ready as a daemon"
daemon[:run].call
else
worker_loop_without_daemons worker
end
end
alias_method_chain :worker_loop, :daemons
def awaken_master_with_daemons
if SIG_QUEUE.include? :QUIT
WORKERS.each do |pid, worker|
daemon = WorkerDaemons[worker.nr]
next unless daemon
Process.kill 'TERM', pid
end
end
awaken_master_without_daemons
end
alias_method_chain :awaken_master, :daemons
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment