capistrano-runit 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/README.markdown +1 -0
- data/capistrano-runit.gemspec +12 -0
- data/lib/capistrano-runit/recipes/base.rb +13 -0
- data/lib/capistrano-runit/recipes/delayed_job.rb +36 -0
- data/lib/capistrano-runit/recipes/unicorn.rb +58 -0
- data/lib/capistrano-runit/recipes.rb +3 -0
- data/lib/capistrano-runit/templates/run-delayed_job.erb +3 -0
- data/lib/capistrano-runit/templates/run-unicorn.erb +157 -0
- metadata +91 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.markdown
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
TODO: Write README!
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "capistrano-runit"
|
3
|
+
s.version = "1.0.0"
|
4
|
+
s.summary = "Useful deployment recipes."
|
5
|
+
s.homepage = "http://github.com/antage/capistrano-runit"
|
6
|
+
s.author = "Anton Ageev"
|
7
|
+
s.email = "antage@gmail.com"
|
8
|
+
s.files = `git ls-files`.split
|
9
|
+
s.add_dependency "capistrano", ">= 2.0.0"
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim:ts=2 sw=2 ft=ruby
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Capistrano::Configuration.instance(true).load do
|
2
|
+
_cset :runit_dir, defer { "#{deploy_to}/runit" }
|
3
|
+
|
4
|
+
namespace :runit do
|
5
|
+
desc "Setup runit directories"
|
6
|
+
task :setup, :roles => :app do
|
7
|
+
run "[ -d #{runit_dir}/.env ] || mkdir -p #{runit_dir}/.env"
|
8
|
+
run "echo $HOME > #{runit_dir}/.env/HOME"
|
9
|
+
run "[ -d #{runit_dir}/available ] || mkdir -p #{runit_dir}/available"
|
10
|
+
run "[ -d #{runit_dir}/enabled ] || mkdir -p #{runit_dir}/enabled"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
Capistrano::Configuration.instance(true).load do
|
2
|
+
_cset :runit_delayed_job_service_name, "delayed_job"
|
3
|
+
_cset :runit_delayed_job_template, File.expand_path(File.join(File.dirname(__FILE__), "../templates/run-delayed_job.erb"))
|
4
|
+
_cset :runit_delayed_job_command, "./script/delayed_job"
|
5
|
+
|
6
|
+
namespace :runit do
|
7
|
+
namespace :delayed_job do
|
8
|
+
desc "Setup delayed_job runit-service"
|
9
|
+
task :setup, :roles => :app do
|
10
|
+
run "[ -d #{runit_dir}/available/#{runit_delayed_job_service_name} ] || mkdir -p #{runit_dir}/available/#{runit_delayed_job_service_name}"
|
11
|
+
template = File.read(runit_delayed_job_template)
|
12
|
+
erb_template = ERB.new(template)
|
13
|
+
servers = find_servers_for_task(current_task)
|
14
|
+
servers.each do |server|
|
15
|
+
put erb_template.result(binding), "#{runit_dir}/available/#{runit_delayed_job_service_name}/run", :mode => 0755, :hosts => server.host
|
16
|
+
end
|
17
|
+
find_and_execute_task "runit:delayed_job:enable"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Enable delayed_job runit-service"
|
21
|
+
task :enable, :roles => :app do
|
22
|
+
run "cd #{runit_dir}/enabled && [ -h ./#{runit_delayed_job_service_name} ] || ln -sf ../available/#{runit_delayed_job_service_name} ."
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Disable delayed_job runit-service"
|
26
|
+
task :disable, :roles => :app do
|
27
|
+
run "[ ! -h #{runit_dir}/enabled/#{runit_delayed_job_service_name} ] || sv stop #{runit_dir}/enabled/#{runit_delayed_job_service_name}/ && rm -f #{runit_dir}/enabled/#{runit_delayed_job_service_name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Restart delayed_job runit-service"
|
31
|
+
task :restart, :roles => :app do
|
32
|
+
run "[ ! -h #{runit_dir}/enabled/#{runit_delayed_job_service_name} ] || sv restart #{runit_dir}/enabled/#{runit_delayed_job_service_name}/"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
Capistrano::Configuration.instance(true).load do
|
2
|
+
_cset :runit_unicorn_service_name, "unicorn"
|
3
|
+
_cset :runit_unicorn_template, File.expand_path(File.join(File.dirname(__FILE__), "../templates/run-unicorn.erb"))
|
4
|
+
_cset :runit_unicorn_command, "unicorn"
|
5
|
+
_cset :runit_unicorn_workers, 4
|
6
|
+
_cset :runit_unicorn_listen, "127.0.0.1"
|
7
|
+
_cset :runit_unicorn_port, 8080
|
8
|
+
_cset :runit_unicorn_after_fork_code, ""
|
9
|
+
|
10
|
+
namespace :runit do
|
11
|
+
namespace :unicorn do
|
12
|
+
desc "Setup Unicorn runit-service"
|
13
|
+
task :setup, :roles => :app do
|
14
|
+
run "[ -d #{runit_dir}/available/#{runit_unicorn_service_name} ] || mkdir -p #{runit_dir}/available/#{runit_unicorn_service_name}"
|
15
|
+
template = File.read(runit_unicorn_template)
|
16
|
+
erb_template = ERB.new(template)
|
17
|
+
servers = find_servers_for_task(current_task)
|
18
|
+
servers.each do |server|
|
19
|
+
runit_unicorn_listen_current =
|
20
|
+
if runit_unicorn_listen.is_a?(Hash)
|
21
|
+
runit_unicorn_listen[server.host]
|
22
|
+
else
|
23
|
+
runit_unicorn_listen
|
24
|
+
end
|
25
|
+
runit_unicorn_port_current =
|
26
|
+
if runit_unicorn_port.is_a?(Hash)
|
27
|
+
runit_unicorn_port[server.host]
|
28
|
+
else
|
29
|
+
runit_unicorn_port
|
30
|
+
end
|
31
|
+
runit_unicorn_workers_current =
|
32
|
+
if runit_unicorn_workers.is_a?(Hash)
|
33
|
+
runit_unicorn_workers[server.host]
|
34
|
+
else
|
35
|
+
runit_unicorn_workers
|
36
|
+
end
|
37
|
+
put erb_template.result(binding), "#{runit_dir}/available/#{runit_unicorn_service_name}/run", :mode => 0755, :hosts => server.host
|
38
|
+
end
|
39
|
+
find_and_execute_task "runit:unicorn:enable"
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "Enable Unicorn runit-service"
|
43
|
+
task :enable, :roles => :app do
|
44
|
+
run "cd #{runit_dir}/enabled && [ -h ./#{runit_unicorn_service_name} ] || ln -sf ../available/#{runit_unicorn_service_name} ."
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "Enable Unicorn runit-service"
|
48
|
+
task :disable, :roles => :app do
|
49
|
+
run "[ ! -h #{runit_dir}/enabled/#{runit_unicorn_service_name} ] || sv stop #{runit_dir}/enabled/#{runit_unicorn_service_name}/ && rm -f #{runit_dir}/enabled/#{runit_unicorn_service_name}"
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Restart Unicorn runit-service"
|
53
|
+
task :restart, :roles => :app do
|
54
|
+
run "[ ! -h #{runit_dir}/enabled/#{runit_unicorn_service_name} ] || sv restart #{runit_dir}/enabled/#{runit_unicorn_service_name}/"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
#!/bin/bash -e
|
2
|
+
|
3
|
+
#
|
4
|
+
# Supervises unicorn; stopping this service prompts a graceful shutdown of the
|
5
|
+
# current unicorn instance. Sending HUP to this service causes unicorn to re-exec
|
6
|
+
# itself for upgrades etc.
|
7
|
+
#
|
8
|
+
|
9
|
+
ADDR=<%= runit_unicorn_listen_current %>
|
10
|
+
PORT=<%= runit_unicorn_port_current %>
|
11
|
+
APP_DIR="<%= current_path %>"
|
12
|
+
THIS_DIR=$(pwd)
|
13
|
+
CUR_PID_FILE=$APP_DIR/tmp/pids/unicorn.pid
|
14
|
+
OLD_PID_FILE=$CUR_PID_FILE.oldbin
|
15
|
+
|
16
|
+
|
17
|
+
if [ ! -d "$APP_DIR" ]; then
|
18
|
+
echo "no such app dir: $APP_DIR" 1>&2;
|
19
|
+
exit 2
|
20
|
+
fi
|
21
|
+
|
22
|
+
cat <<EOF > unicorn.rb
|
23
|
+
working_directory "$APP_DIR"
|
24
|
+
pid "$CUR_PID_FILE"
|
25
|
+
|
26
|
+
worker_processes <%= runit_unicorn_workers_current %>
|
27
|
+
|
28
|
+
preload_app true
|
29
|
+
|
30
|
+
# Restart any workers that haven't responded in 30 seconds
|
31
|
+
timeout 60
|
32
|
+
|
33
|
+
# listen on both a Unix domain socket and a TCP port,
|
34
|
+
#listen '$THIS_DIR/socket', :backlog => 64
|
35
|
+
listen '$ADDR:$PORT', :tcp_nopush => true
|
36
|
+
|
37
|
+
stderr_path "log/unicorn.stderr.log"
|
38
|
+
stdout_path "log/unicorn.stdout.log"
|
39
|
+
|
40
|
+
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
41
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
42
|
+
GC.copy_on_write_friendly = true
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
before_fork do |server, worker|
|
47
|
+
# the following is highly recomended for Rails + "preload_app true"
|
48
|
+
# as there's no need for the master process to hold a connection
|
49
|
+
if defined?(::ActiveRecord::Base)
|
50
|
+
::ActiveRecord::Base.connection.disconnect!
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
|
55
|
+
# immediately start loading up a new version of itself (loaded with a new
|
56
|
+
# version of our app). When this new Unicorn is completely loaded
|
57
|
+
# it will begin spawning workers. The first worker spawned will check to
|
58
|
+
# see if an .oldbin pidfile exists. If so, this means we've just booted up
|
59
|
+
# a new Unicorn and need to tell the old one that it can now die. To do so
|
60
|
+
# we send it a QUIT.
|
61
|
+
#
|
62
|
+
# Using this method we get 0 downtime deploys.
|
63
|
+
|
64
|
+
old_pid = "$APP_DIR/tmp/pids/unicorn.pid.oldbin"
|
65
|
+
if File.exists?(old_pid) && server.pid != old_pid
|
66
|
+
begin
|
67
|
+
puts "Shutting down old process"
|
68
|
+
Process.kill("QUIT", File.read(old_pid).to_i)
|
69
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
70
|
+
# someone else did our job for us
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
after_fork do |server, worker|
|
77
|
+
##
|
78
|
+
# Unicorn master loads the app then forks off workers - because of the way
|
79
|
+
# Unix forking works, we need to make sure we aren't using any of the parent's
|
80
|
+
# sockets, e.g. db connection
|
81
|
+
|
82
|
+
if defined?(::ActiveRecord::Base)
|
83
|
+
::ActiveRecord::Base.establish_connection
|
84
|
+
end
|
85
|
+
|
86
|
+
# Redis and Memcached would go here but their connections are established
|
87
|
+
# on demand, so the master never opens a socket
|
88
|
+
<% unless fetch(:runit_unicorn_after_fork_code, nil).nil? %>
|
89
|
+
<%= runit_unicorn_after_fork_code %>
|
90
|
+
<% end %>
|
91
|
+
end
|
92
|
+
EOF
|
93
|
+
|
94
|
+
function is_pid_running() {
|
95
|
+
set +e
|
96
|
+
if [ -n $1 ] && kill -0 $1 >/dev/null 2>&1; then
|
97
|
+
echo "yes"
|
98
|
+
fi
|
99
|
+
set -e
|
100
|
+
}
|
101
|
+
|
102
|
+
echo "My pid: $$"
|
103
|
+
|
104
|
+
if [ -e $OLD_PID_FILE ]; then
|
105
|
+
OLD_PID=$(cat $OLD_PID_FILE)
|
106
|
+
echo "Unicorn appears to be restarting: waiting for old master ($OLD_PID) to exit"
|
107
|
+
while [ -n "$(is_pid_running $OLD_PID)" ]; do
|
108
|
+
/bin/echo -n '.'
|
109
|
+
sleep 2
|
110
|
+
done
|
111
|
+
fi
|
112
|
+
|
113
|
+
if [ -e $CUR_PID_FILE ]; then
|
114
|
+
CUR_PID=$(cat $CUR_PID_FILE)
|
115
|
+
if [ -n "$(is_pid_running $CUR_PID)" ]; then
|
116
|
+
echo "Already running as $CUR_PID"
|
117
|
+
RUNNING=true
|
118
|
+
fi
|
119
|
+
fi
|
120
|
+
|
121
|
+
if [ ! $RUNNING ]; then
|
122
|
+
echo "Starting unicorn"
|
123
|
+
old=$(pwd)
|
124
|
+
cd $APP_DIR
|
125
|
+
<%= runit_unicorn_command %> -E production -c $THIS_DIR/unicorn.rb -D
|
126
|
+
cd $old
|
127
|
+
sleep 2
|
128
|
+
CUR_PID=$(cat $CUR_PID_FILE)
|
129
|
+
fi
|
130
|
+
|
131
|
+
function restart() {
|
132
|
+
# TODO: regenerate config if this file has changed
|
133
|
+
|
134
|
+
# Tell unicorn to re-exec itself
|
135
|
+
echo "Asking unicorn to re-exec itself with USR2"
|
136
|
+
kill -USR2 $CUR_PID
|
137
|
+
# Wait and then exit -- after runit restarts the script, we'll
|
138
|
+
# wait for the re-exec'd process
|
139
|
+
sleep 2
|
140
|
+
echo "Restarting to supervise new unicorn"
|
141
|
+
exit
|
142
|
+
}
|
143
|
+
|
144
|
+
function graceful_shutdown() {
|
145
|
+
echo "Requesting graceful shutdown"
|
146
|
+
kill -QUIT $CUR_PID
|
147
|
+
}
|
148
|
+
|
149
|
+
trap restart HUP QUIT
|
150
|
+
trap graceful_shutdown INT TERM
|
151
|
+
|
152
|
+
echo "Watching for unicorn ($CUR_PID) exiting"
|
153
|
+
while [ -n "$(is_pid_running $CUR_PID)" ]; do
|
154
|
+
/bin/echo -n '.'
|
155
|
+
sleep 2
|
156
|
+
done
|
157
|
+
echo "Unicorn has exited."
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: capistrano-runit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Anton Ageev
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-15 00:00:00 +04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: capistrano
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 2.0.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description:
|
38
|
+
email: antage@gmail.com
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Gemfile
|
48
|
+
- README.markdown
|
49
|
+
- capistrano-runit.gemspec
|
50
|
+
- lib/capistrano-runit/recipes.rb
|
51
|
+
- lib/capistrano-runit/recipes/base.rb
|
52
|
+
- lib/capistrano-runit/recipes/delayed_job.rb
|
53
|
+
- lib/capistrano-runit/recipes/unicorn.rb
|
54
|
+
- lib/capistrano-runit/templates/run-delayed_job.erb
|
55
|
+
- lib/capistrano-runit/templates/run-unicorn.erb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/antage/capistrano-runit
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
hash: 3
|
80
|
+
segments:
|
81
|
+
- 0
|
82
|
+
version: "0"
|
83
|
+
requirements: []
|
84
|
+
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 1.6.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 3
|
89
|
+
summary: Useful deployment recipes.
|
90
|
+
test_files: []
|
91
|
+
|