capistrano-runit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|