Skip to content

Instantly share code, notes, and snippets.

@jtomaszewski
Last active October 21, 2015 17:22
Show Gist options
  • Save jtomaszewski/2bb75634200a41683afc to your computer and use it in GitHub Desktop.
Save jtomaszewski/2bb75634200a41683afc to your computer and use it in GitHub Desktop.
Eye configuration for unicorn && sidekiq
# ...
namespace :deploy do
desc 'Restart application'
task :restart => ["eye:reload", "eye:restart"]
after :published, :restart
end
#!/bin/sh
#
# This file was generated by chef
#
### BEGIN INIT INFO
# Provides: sampleapp
# Required-Start: $network $remote_fs $syslog $local_fs
# Required-Stop: $network $remote_fs $syslog $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts sampleapp by eye
### END INIT INFO
EYE="PATH=/opt/rbenv/shims:/opt/rbenv/bin:$PATH RBENV_ROOT=/opt/rbenv RBENV_VERSION=2.2.0 /opt/rbenv/bin/rbenv exec eye"
CONFIG_FILE=/u/apps/sampleapp/current/config/eye.rb
SERVICE_NAME=sampleapp
RUNAS=deploy
execute() {
CMD="$EYE $1 $2"
if [ "$USER" = "$RUNAS" ]; then
env $CMD
else
su $RUNAS -c "$CMD"
fi
}
case "$1" in
start)
echo -n "Loading eye configuration for $SERVICE_NAME"
execute load $CONFIG_FILE
echo -n "Starting eye's application $SERVICE_NAME"
execute start $SERVICE_NAME
;;
stop)
echo -n "Stopping eye's application $SERVICE_NAME"
execute stop $SERVICE_NAME
;;
restart)
echo -n "Loading eye configuration for $SERVICE_NAME"
execute load $CONFIG_FILE
echo -n "Restarting eye's application $SERVICE_NAME"
execute restart $SERVICE_NAME
;;
reload)
echo -n "Reloading eye configuration for $SERVICE_NAME"
execute quit
execute load $CONFIG_FILE
;;
status)
execute info $SERVICE_NAME
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status}"
exit 1
;;
esac
namespace :eye do
%i[start stop restart reload status].each do |task_name|
desc "#{task_name.to_s.capitalize} eye-sampleapp service."
task task_name do
on roles(:web) do
execute "/etc/init.d/eye-sampleapp #{task_name}"
end
end
end
end
APPLICATION_NAME = 'sampleapp'
APP_PATH = File.expand_path("..", File.dirname(__FILE__))
# Because:
# - Eye has some really strong problems with proper loading of ENV variables,
# - APP_PATH will be logical location of app (that is: release_path, not current_path)
# we have to enforce APP_PATH to be equal to current_path on environments which are being updated with capistrano.
env_file = "#{APP_PATH}/.env"
RAILS_ENV = ENV['RAILS_ENV'] || (File.exists?(env_file) ? File.read(env_file).match(/RAILS_ENV\=([A-z]+)/)[1] : nil) || 'production'
APP_PATH = "/u/apps/#{APPLICATION_NAME}/current" if %w[staging production].include?(RAILS_ENV)
Eye.config do
logger "#{APP_PATH}/log/eye.log"
end
Eye.application APPLICATION_NAME do
memory_rails_instance_check_options = { every: 1.minute, below: 250.megabytes, times: [3, 5] }
cpu_rails_instance_check_options = { every: 10.seconds, below: 50, times: [3, 5] }
working_dir APP_PATH
env "RAILS_ENV" => RAILS_ENV
env "PATH" => "/opt/rbenv/shims:/opt/rbenv/bin:#{ENV['PATH']}"
env "RBENV_ROOT" => "/opt/rbenv"
env "RBENV_VERSION" => File.read("#{APP_PATH}/.ruby-version").strip
env "BUNDLE_GEMFILE" => "#{APP_PATH}/Gemfile"
trigger :flapping, times: 10, within: 1.minute, retry_in: 10.minutes
check :cpu, every: 10.seconds, below: 100, times: 3
process :unicorn do
pid_file "tmp/pids/unicorn.pid"
start_command "bundle exec unicorn config.ru -Dc config/unicorn.rb -E #{RAILS_ENV}"
# Tell unicorn to finish his current requests, wait a little and then kill it.
stop_signals [:QUIT, 10.seconds, :TERM]
# Unicorn will restart the binary itself.
restart_command "kill -USR2 {PID}"
start_timeout 30.seconds
restart_grace 30.seconds
stdall "log/eye.unicorn.log"
check :memory, memory_rails_instance_check_options
monitor_children do
check :cpu, cpu_rails_instance_check_options
check :memory, memory_rails_instance_check_options
stop_command "kill -QUIT {PID}"
end
end
process :sidekiq do
pid_file "tmp/pids/sidekiq.pid"
start_command "bundle exec sidekiq -d -e #{RAILS_ENV} -L log/sidekiq.log -C config/sidekiq.yml"
# Tell sidekiq to finish his current jobs and stop taking next jobs,
# wait a little and then tell sidekiq to kill his running jobs.
stop_signals [:USR1, 30.seconds, :TERM]
# Sidekiq will wait {sidekiq.yml#timeout} seconds after getting TERM signal with killing itself.
# Let's wait a bit more than that.
stop_grace 15.seconds
start_timeout 30.seconds
start_grace 30.seconds
stdall "log/eye.sidekiq.log"
check :memory, memory_rails_instance_check_options
monitor_children do
check :cpu, cpu_rails_instance_check_options
check :memory, memory_rails_instance_check_options
stop_command "kill -QUIT {PID}"
end
end
end
RAILS_ENV = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'production'
APPLICATION_NAME = 'sampleapp'
if RAILS_ENV == 'development'
app_path = File.expand_path('..', File.dirname(__FILE__))
shared_app_path = current_app_path = app_path
else
app_path = "/u/apps/#{APPLICATION_NAME}"
shared_app_path = "#{app_path}/shared"
current_app_path = "#{app_path}/current"
end
if RAILS_ENV == 'development'
worker_processes 1
timeout Integer(ENV['UNICORN_WEB_TIMEOUT'] || 60)
listen 3000
stderr_path "log/unicorn.log"
stdout_path "log/unicorn.log"
else
worker_processes Integer(ENV['UNICORN_WEB_CONCURRENCY'] || 3)
timeout Integer(ENV['UNICORN_WEB_TIMEOUT'] || 45)
stderr_path "log/unicorn.log"
stdout_path "log/unicorn.log"
end
logger Logger.new(ENV['LOG_FILE'] || STDERR)
preload_app true
listen (ENV['UNICORN_SOCK'] || "#{shared_app_path}/tmp/sockets/unicorn.sock"), backlog: 64
pid (ENV['UNICORN_PIDFILE'] || "#{shared_app_path}/tmp/pids/unicorn.pid")
ENV['BUNDLE_GEMFILE'] = "#{current_app_path}/Gemfile"
# Forcibly clean environment variables between bundlings
# http://www.mail-archive.com/mongrel-unicorn@rubyforge.org/msg00276.html
before_exec do |_|
# ENV["GEM_HOME"] = ENV['GEM_PATH'] = "#{app_path}/shared/bundle"
ENV["BUNDLE_GEMFILE"] = "#{current_app_path}/Gemfile"
end
before_fork do |server, worker|
ActiveRecord::Base.connection.disconnect!
##
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
# immediately start loading up a new version of itself (loaded with a new
# version of our app). When this new Unicorn is completely loaded
# it will begin spawning workers. The first worker spawned will check to
# see if an .oldbin pidfile exists. If so, this means we've just booted up
# a new Unicorn and need to tell the old one that it can now die. To do so
# we send it a QUIT.
#
# Using this method we get 0 downtime deploys.
old_pid = "#{shared_app_path}/tmp/pids/unicorn.pid.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? "QUIT" : "TTOU"
puts "Sending #{sig} signal to old unicorn master..."
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
# Throttle the master from forking too quickly (for incremental kill-off only)
sleep 1
end
after_fork do |server, worker|
ActiveRecord::Base.establish_connection
NewRelic::Agent.shutdown if defined?(NewRelic)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment