Last active
October 21, 2015 17:22
-
-
Save jtomaszewski/2bb75634200a41683afc to your computer and use it in GitHub Desktop.
Eye configuration for unicorn && sidekiq
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ... | |
namespace :deploy do | |
desc 'Restart application' | |
task :restart => ["eye:reload", "eye:restart"] | |
after :published, :restart | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/[email protected]/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