thin 0.6.1-x86-mswin32-60 → 0.6.2-x86-mswin32-60
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of thin might be problematic. Click here for more details.
- data/CHANGELOG +24 -0
- data/benchmark/simple.rb +4 -3
- data/benchmark/utils.rb +1 -1
- data/bin/thin +24 -16
- data/example/adapter.rb +25 -7
- data/example/monit_sockets +20 -0
- data/example/monit_unixsock +20 -0
- data/lib/thin.rb +1 -0
- data/lib/thin/cluster.rb +13 -23
- data/lib/thin/command.rb +40 -0
- data/lib/thin/connection.rb +12 -7
- data/lib/thin/daemonizing.rb +47 -20
- data/lib/thin/headers.rb +4 -1
- data/lib/thin/logging.rb +1 -0
- data/lib/thin/request.rb +21 -14
- data/lib/thin/response.rb +30 -7
- data/lib/thin/server.rb +48 -22
- data/lib/thin/stats.rb +258 -19
- data/lib/thin/version.rb +14 -2
- data/lib/thin_parser.so +0 -0
- data/spec/cluster_spec.rb +66 -38
- data/spec/command_spec.rb +15 -0
- data/spec/daemonizing_spec.rb +3 -0
- data/spec/request_spec.rb +13 -3
- data/spec/response_spec.rb +2 -2
- data/spec/server_spec.rb +44 -10
- data/tasks/gem.rake +2 -8
- metadata +6 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
== 0.6.2 Rambo release
|
2
|
+
* Server now let current connections finish before stopping, fixes #18
|
3
|
+
* Fix uploading hanging bug when body is moved to a tempfile,
|
4
|
+
also delete the tempfile properly upon completion, fixes #25
|
5
|
+
* 'thin restart' now sends HUP signals rather then stopping & starting, closes #17
|
6
|
+
* HUP signal now launches a new process with the same options.
|
7
|
+
* Add PID and more info from the last request to the Stats adapter
|
8
|
+
mostly taken from Rack::ShowException.
|
9
|
+
* pid and log files in cluster are no longer required to be relative to the
|
10
|
+
app directory (chdir option), fixes #24
|
11
|
+
* Revert to using #each when building response headers under Ruby 1.8,
|
12
|
+
solves an issue w/ Camping adapter, fixes #22
|
13
|
+
* Restructure thin script options in 3 sections: server, daemon and cluster
|
14
|
+
* Add --only (-o) option to control only one server of a cluster.
|
15
|
+
* Stylize stats page and make the url configurable from the thin script.
|
16
|
+
* Raise error if attempting to use unix sockets on windows.
|
17
|
+
* Add example config files for http://www.tildeslash.com/monit useage.
|
18
|
+
Include the example file using "include /path/to/thin/monit/file" in your monitrc file.
|
19
|
+
The group settings let you do this to manage your clusters:
|
20
|
+
|
21
|
+
sudo monit -g blog restart all
|
22
|
+
|
23
|
+
There are examples of thin listening on sockets and thin listening on unix sockets.
|
24
|
+
|
1
25
|
== 0.6.1 Cheesecake release
|
2
26
|
* Remove socket file when server stops.
|
3
27
|
* Set back cluster to use 'thin' command to launch servers.
|
data/benchmark/simple.rb
CHANGED
@@ -3,12 +3,13 @@
|
|
3
3
|
#
|
4
4
|
# Run with:
|
5
5
|
#
|
6
|
-
# ruby simple.rb [num of request]
|
6
|
+
# ruby simple.rb [num of request] [print|graph] [concurrency levels]
|
7
7
|
#
|
8
8
|
require File.dirname(__FILE__) + '/../lib/thin'
|
9
9
|
require File.dirname(__FILE__) + '/utils'
|
10
10
|
|
11
|
-
request
|
11
|
+
request = (ARGV[0] || 1000).to_i # Number of request to send (ab -n option)
|
12
12
|
output_type = (ARGV[1] || 'print')
|
13
|
+
levels = eval(ARGV[2] || '[1, 10, 100]').to_a
|
13
14
|
|
14
|
-
benchmark output_type, %w(WEBrick Mongrel EMongrel Thin), request,
|
15
|
+
benchmark output_type, %w(WEBrick Mongrel EMongrel Thin), request, levels
|
data/benchmark/utils.rb
CHANGED
@@ -29,7 +29,7 @@ def run(handler_name, n=1000, c=1)
|
|
29
29
|
|
30
30
|
sleep 2
|
31
31
|
|
32
|
-
out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1
|
32
|
+
out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:#{port}/ 2> /dev/null`
|
33
33
|
|
34
34
|
Process.kill('SIGKILL', server)
|
35
35
|
Process.wait
|
data/bin/thin
CHANGED
@@ -34,20 +34,29 @@ opts = OptionParser.new do |opts|
|
|
34
34
|
opts.on("-S", "--socket PATH", "bind to unix domain socket") { |file| options[:socket] = file }
|
35
35
|
opts.on("-e", "--environment ENV", "Rails environment (default: development)") { |env| options[:environment] = env }
|
36
36
|
opts.on("-c", "--chdir PATH", "Change to dir before starting") { |dir| options[:chdir] = File.expand_path(dir) }
|
37
|
-
opts.on("-
|
38
|
-
"
|
37
|
+
opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
|
38
|
+
"(default: #{options[:timeout]})") { |sec| options[:timeout] = sec.to_i }
|
39
|
+
opts.on( "--prefix PATH", "Mount the app under PATH (start with /)") { |path| options[:prefix] = path }
|
40
|
+
opts.on( "--stats PATH", "Mount the Stats adapter under PATH") { |path| options[:stats] = path }
|
41
|
+
|
42
|
+
opts.separator ""
|
43
|
+
opts.separator "Daemon options:"
|
44
|
+
|
39
45
|
opts.on("-d", "--daemonize", "Run daemonized in the background") { options[:daemonize] = true }
|
40
46
|
opts.on("-l", "--log FILE", "File to redirect output",
|
41
47
|
"(default: #{options[:log]})") { |file| options[:log] = file }
|
42
48
|
opts.on("-P", "--pid FILE", "File to store PID",
|
43
49
|
"(default: #{options[:pid]})") { |file| options[:pid] = file }
|
44
|
-
opts.on("-t", "--timeout SEC", "Request or command timeout in sec",
|
45
|
-
"(default: #{options[:timeout]})") { |sec| options[:timeout] = sec.to_i }
|
46
50
|
opts.on("-u", "--user NAME", "User to run daemon as (use with -g)") { |user| options[:user] = user }
|
47
51
|
opts.on("-g", "--group NAME", "Group to run daemon as (use with -u)") { |group| options[:group] = group }
|
48
|
-
|
49
|
-
opts.
|
50
|
-
opts.
|
52
|
+
|
53
|
+
opts.separator ""
|
54
|
+
opts.separator "Cluster options:"
|
55
|
+
|
56
|
+
opts.on("-s", "--servers NUM", "Number of servers to start",
|
57
|
+
"set a value >1 to start a cluster") { |num| options[:servers] = num.to_i }
|
58
|
+
opts.on("-o", "--only NUM", "Send command to only one server of the cluster") { |only| options[:only] = only }
|
59
|
+
opts.on("-C", "--config PATH", "Load options from a config file") { |file| options[:config] = file }
|
51
60
|
|
52
61
|
opts.separator ""
|
53
62
|
opts.separator "Common options:"
|
@@ -62,7 +71,7 @@ end
|
|
62
71
|
# == Utilities
|
63
72
|
|
64
73
|
def cluster?(options)
|
65
|
-
options[:servers] && options[:servers] > 1
|
74
|
+
options[:only] || (options[:servers] && options[:servers] > 1)
|
66
75
|
end
|
67
76
|
|
68
77
|
def load_options_from_config_file!(options)
|
@@ -101,9 +110,12 @@ def start(options)
|
|
101
110
|
server.app = Rack::URLMap.new(options[:prefix] => server.app) if options[:prefix]
|
102
111
|
|
103
112
|
# If a stats are required, wrap in Stats adapter
|
104
|
-
server.app = Thin::Stats::Adapter.new(server.app) if options[:stats]
|
113
|
+
server.app = Thin::Stats::Adapter.new(server.app, options[:stats]) if options[:stats]
|
105
114
|
|
106
|
-
|
115
|
+
# Register restart procedure
|
116
|
+
server.on_restart { Thin::Command.run(:start, options) }
|
117
|
+
|
118
|
+
server.start
|
107
119
|
end
|
108
120
|
end
|
109
121
|
|
@@ -113,7 +125,7 @@ def stop(options)
|
|
113
125
|
if cluster?(options)
|
114
126
|
Thin::Cluster.new(options).stop
|
115
127
|
else
|
116
|
-
Thin::Server.kill
|
128
|
+
Thin::Server.kill(options[:pid], options[:timeout])
|
117
129
|
end
|
118
130
|
end
|
119
131
|
|
@@ -123,11 +135,7 @@ def restart(options)
|
|
123
135
|
if cluster?(options)
|
124
136
|
Thin::Cluster.new(options).restart
|
125
137
|
else
|
126
|
-
|
127
|
-
options.update :daemonize => true
|
128
|
-
|
129
|
-
stop(options)
|
130
|
-
start(options)
|
138
|
+
Thin::Server.restart(options[:pid])
|
131
139
|
end
|
132
140
|
end
|
133
141
|
|
data/example/adapter.rb
CHANGED
@@ -1,17 +1,35 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Run with: ruby adapter.rb
|
2
|
+
# Then browse to http://localhost:3000/test
|
3
|
+
# and http://localhost:3000/files/adapter.rb
|
4
|
+
require File.dirname(__FILE__) + '/../lib/thin'
|
3
5
|
|
4
6
|
class SimpleAdapter
|
5
7
|
def call(env)
|
8
|
+
body = ["hello!"]
|
6
9
|
[
|
7
10
|
200,
|
8
|
-
{
|
9
|
-
|
11
|
+
{
|
12
|
+
'Content-Type' => 'text/plain',
|
13
|
+
'Content-Type' => body.join.size.to_s
|
14
|
+
},
|
15
|
+
body
|
10
16
|
]
|
11
17
|
end
|
12
18
|
end
|
13
19
|
|
14
|
-
|
15
|
-
|
20
|
+
Thin::Server.start('0.0.0.0', 3000) do
|
21
|
+
use Rack::CommonLogger
|
22
|
+
map '/test' do
|
23
|
+
run SimpleAdapter.new
|
24
|
+
end
|
25
|
+
map '/files' do
|
26
|
+
run Rack::File.new('.')
|
27
|
+
end
|
28
|
+
end
|
16
29
|
|
17
|
-
|
30
|
+
# You could also start the server like this:
|
31
|
+
#
|
32
|
+
# app = Rack::URLMap.new('/test' => SimpleAdapter.new,
|
33
|
+
# '/files' => Rack::File.new('.'))
|
34
|
+
# Thin::Server.new('0.0.0.0', 3000, app).start
|
35
|
+
#
|
@@ -0,0 +1,20 @@
|
|
1
|
+
check process blog1
|
2
|
+
with pidfile /u/apps/blog/shared/pids/thin.14000.pid
|
3
|
+
start program = "/usr/local/bin/ruby /usr/local/bin/thin start -d -e production -u nobody -g nobody -p 14000 -a 127.0.0.1 -P tmp/pids/thin.14000.pid -c /u/apps/blog/current"
|
4
|
+
stop program = "/usr/local/bin/ruby /usr/local/bin/thin stop -P /u/apps/blog/shared/pids/thin.14000.pid"
|
5
|
+
if totalmem > 90.0 MB for 5 cycles then restart
|
6
|
+
if failed port 14000 then restart
|
7
|
+
if cpu usage > 95% for 3 cycles then restart
|
8
|
+
if 5 restarts within 5 cycles then timeout
|
9
|
+
group blog
|
10
|
+
|
11
|
+
check process blog2
|
12
|
+
with pidfile /u/apps/blog/shared/pids/thin.14001.pid
|
13
|
+
start program = "/usr/local/bin/ruby /usr/local/bin/thin start -d -e production -u nobody -g nobody -p 14001 -a 127.0.0.1 -P tmp/pids/thin.14001.pid -c /u/apps/blog/current"
|
14
|
+
stop program = "/usr/local/bin/ruby /usr/local/bin/thin stop -P /u/apps/blog/shared/pids/thin.14001.pid"
|
15
|
+
if totalmem > 90.0 MB for 5 cycles then restart
|
16
|
+
if failed port 14001 then restart
|
17
|
+
if cpu usage > 95% for 3 cycles then restart
|
18
|
+
if 5 restarts within 5 cycles then timeout
|
19
|
+
group blog
|
20
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
check process blog1
|
2
|
+
with pidfile /u/apps/blog/shared/pids/thin.1.pid
|
3
|
+
start program = "/usr/local/bin/ruby /usr/local/bin/thin start -d -e production -S /u/apps/blog/shared/pids/thin.1.sock -P tmp/pids/thin.1.pid -c /u/apps/blog/current"
|
4
|
+
stop program = "/usr/local/bin/ruby /usr/local/bin/thin stop -P /u/apps/blog/shared/pids/thin.1.pid"
|
5
|
+
if totalmem > 90.0 MB for 5 cycles then restart
|
6
|
+
if failed unixsocket /u/apps/blog/shared/pids/thin.1.sock then restart
|
7
|
+
if cpu usage > 95% for 3 cycles then restart
|
8
|
+
if 5 restarts within 5 cycles then timeout
|
9
|
+
group blog
|
10
|
+
|
11
|
+
check process blog2
|
12
|
+
with pidfile /u/apps/blog/shared/pids/thin.2.pid
|
13
|
+
start program = "/usr/local/bin/ruby /usr/local/bin/thin start -d -e production -S /u/apps/blog/shared/pids/thin.2.sock -P tmp/pids/thin.2.pid -c /u/apps/blog/current"
|
14
|
+
stop program = "/usr/local/bin/ruby /usr/local/bin/thin stop -P /u/apps/blog/shared/pids/thin.2.pid"
|
15
|
+
if totalmem > 90.0 MB for 5 cycles then restart
|
16
|
+
if failed unixsocket /u/apps/blog/shared/pids/thin.2.sock then restart
|
17
|
+
if cpu usage > 95% for 3 cycles then restart
|
18
|
+
if 5 restarts within 5 cycles then timeout
|
19
|
+
group blog
|
20
|
+
|
data/lib/thin.rb
CHANGED
@@ -15,6 +15,7 @@ module Thin
|
|
15
15
|
SERVER = "#{NAME} #{VERSION::STRING} codename #{VERSION::CODENAME}".freeze
|
16
16
|
|
17
17
|
autoload :Cluster, 'thin/cluster'
|
18
|
+
autoload :Command, 'thin/command'
|
18
19
|
autoload :Connection, 'thin/connection'
|
19
20
|
autoload :Daemonizable, 'thin/daemonizing'
|
20
21
|
autoload :Logging, 'thin/logging'
|
data/lib/thin/cluster.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Thin
|
2
2
|
# Control a set of servers.
|
3
3
|
# * Generate start and stop commands and run them.
|
4
|
-
# * Inject the port number in the pid and log filenames.
|
5
|
-
# Servers are started throught the +thin+
|
4
|
+
# * Inject the port or socket number in the pid and log filenames.
|
5
|
+
# Servers are started throught the +thin+ command-line script.
|
6
6
|
class Cluster
|
7
7
|
include Logging
|
8
8
|
|
@@ -20,7 +20,8 @@ module Thin
|
|
20
20
|
def initialize(options)
|
21
21
|
@options = options.merge(:daemonize => true)
|
22
22
|
@size = @options.delete(:servers)
|
23
|
-
@
|
23
|
+
@only = @options.delete(:only)
|
24
|
+
@script = $PROGRAM_NAME
|
24
25
|
|
25
26
|
if socket
|
26
27
|
@options.delete(:address)
|
@@ -31,8 +32,8 @@ module Thin
|
|
31
32
|
def first_port; @options[:port] end
|
32
33
|
def address; @options[:address] end
|
33
34
|
def socket; @options[:socket] end
|
34
|
-
def pid_file;
|
35
|
-
def log_file;
|
35
|
+
def pid_file; @options[:pid] end
|
36
|
+
def log_file; @options[:log] end
|
36
37
|
|
37
38
|
# Start the servers
|
38
39
|
def start
|
@@ -99,27 +100,16 @@ module Thin
|
|
99
100
|
else
|
100
101
|
cmd_options.merge!(:port => number)
|
101
102
|
end
|
102
|
-
|
103
|
-
trace shell_cmd
|
104
|
-
ouput = `#{shell_cmd}`.chomp
|
105
|
-
log " " + ouput.gsub("\n", " \n") unless ouput.empty?
|
106
|
-
end
|
107
|
-
|
108
|
-
# Turn into a runnable shell command
|
109
|
-
def shellify(cmd, options)
|
110
|
-
shellified_options = options.inject([]) do |args, (name, value)|
|
111
|
-
args << case value
|
112
|
-
when NilClass
|
113
|
-
when TrueClass then "--#{name}"
|
114
|
-
else "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
|
115
|
-
end
|
116
|
-
end
|
117
|
-
"#{@script} #{cmd} #{shellified_options.compact.join(' ')}"
|
103
|
+
Command.run(cmd, cmd_options)
|
118
104
|
end
|
119
105
|
|
120
106
|
def with_each_server
|
121
|
-
@
|
122
|
-
yield
|
107
|
+
if @only
|
108
|
+
yield @only
|
109
|
+
else
|
110
|
+
@size.times do |n|
|
111
|
+
yield socket ? n : (first_port + n)
|
112
|
+
end
|
123
113
|
end
|
124
114
|
end
|
125
115
|
|
data/lib/thin/command.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Thin
|
2
|
+
# Run a command though the +thin+ command-line script.
|
3
|
+
class Command
|
4
|
+
include Logging
|
5
|
+
|
6
|
+
# Path to the +thin+ script used to control the servers.
|
7
|
+
# Leave this to default to use the one in the path.
|
8
|
+
attr_accessor :script
|
9
|
+
|
10
|
+
def initialize(name, options={})
|
11
|
+
@name = name
|
12
|
+
@options = options
|
13
|
+
@script = $PROGRAM_NAME
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.run(*args)
|
17
|
+
new(*args).run
|
18
|
+
end
|
19
|
+
|
20
|
+
# Send the command to the +thin+ script
|
21
|
+
def run
|
22
|
+
shell_cmd = shellify
|
23
|
+
trace shell_cmd
|
24
|
+
ouput = `#{shell_cmd}`.chomp
|
25
|
+
log " " + ouput.gsub("\n", " \n") unless ouput.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Turn into a runnable shell command
|
29
|
+
def shellify
|
30
|
+
shellified_options = @options.inject([]) do |args, (name, value)|
|
31
|
+
args << case value
|
32
|
+
when NilClass
|
33
|
+
when TrueClass then "--#{name}"
|
34
|
+
else "--#{name.to_s.tr('_', '-')}=#{value.inspect}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
"#{@script} #{@name} #{shellified_options.compact.join(' ')}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/thin/connection.rb
CHANGED
@@ -10,6 +10,9 @@ module Thin
|
|
10
10
|
# +true+ if the connection is on a UNIX domain socket.
|
11
11
|
attr_accessor :unix_socket
|
12
12
|
|
13
|
+
# Server owning the connection
|
14
|
+
attr_accessor :server
|
15
|
+
|
13
16
|
def post_init
|
14
17
|
@request = Request.new
|
15
18
|
@response = Response.new
|
@@ -25,13 +28,11 @@ module Thin
|
|
25
28
|
end
|
26
29
|
|
27
30
|
def process
|
28
|
-
env = @request.env
|
29
|
-
|
30
31
|
# Add client info to the request env
|
31
|
-
env[Request::REMOTE_ADDR] = remote_address
|
32
|
+
@request.env[Request::REMOTE_ADDR] = remote_address
|
32
33
|
|
33
34
|
# Process the request
|
34
|
-
@response.status, @response.headers, @response.body = @app.call(env)
|
35
|
+
@response.status, @response.headers, @response.body = @app.call(@request.env)
|
35
36
|
|
36
37
|
# Send the response
|
37
38
|
@response.each do |chunk|
|
@@ -46,13 +47,17 @@ module Thin
|
|
46
47
|
log_error e
|
47
48
|
close_connection rescue nil
|
48
49
|
ensure
|
49
|
-
@request.close
|
50
|
+
@request.close rescue nil
|
50
51
|
@response.close rescue nil
|
51
52
|
end
|
52
53
|
|
54
|
+
def unbind
|
55
|
+
@server.connection_finished(self)
|
56
|
+
end
|
57
|
+
|
53
58
|
protected
|
54
|
-
def remote_address
|
55
|
-
if remote_addr = env[Request::FORWARDED_FOR]
|
59
|
+
def remote_address
|
60
|
+
if remote_addr = @request.env[Request::FORWARDED_FOR]
|
56
61
|
remote_addr
|
57
62
|
elsif @unix_socket
|
58
63
|
# FIXME not sure about this, does it even make sense on a UNIX socket?
|
data/lib/thin/daemonizing.rb
CHANGED
@@ -31,7 +31,7 @@ module Thin
|
|
31
31
|
|
32
32
|
# Turns the current script into a daemon process that detaches from the console.
|
33
33
|
def daemonize
|
34
|
-
|
34
|
+
raise PlatformNotSupported, 'Daemonizing not supported on Windows' if Thin.win?
|
35
35
|
raise ArgumentError, 'You must specify a pid_file to deamonize' unless @pid_file
|
36
36
|
|
37
37
|
pwd = Dir.pwd # Current directory is changed during daemonization, so store it
|
@@ -39,8 +39,10 @@ module Thin
|
|
39
39
|
Daemonize.daemonize(File.expand_path(@log_file))
|
40
40
|
|
41
41
|
Dir.chdir(pwd)
|
42
|
-
|
42
|
+
|
43
43
|
write_pid_file
|
44
|
+
|
45
|
+
trap('HUP') { restart }
|
44
46
|
at_exit do
|
45
47
|
log ">> Exiting!"
|
46
48
|
remove_pid_file
|
@@ -50,7 +52,6 @@ module Thin
|
|
50
52
|
# Change privileges of the process
|
51
53
|
# to the specified user and group.
|
52
54
|
def change_privilege(user, group=user)
|
53
|
-
check_plateform_support
|
54
55
|
log ">> Changing process privilege to #{user}:#{group}"
|
55
56
|
|
56
57
|
uid, gid = Process.euid, Process.egid
|
@@ -67,41 +68,67 @@ module Thin
|
|
67
68
|
log "Couldn't change user and group to #{user}:#{group}: #{e}"
|
68
69
|
end
|
69
70
|
|
71
|
+
# Registerer a proc to be called to restart the server.
|
72
|
+
def on_restart(&block)
|
73
|
+
@on_restart = block
|
74
|
+
end
|
75
|
+
|
76
|
+
# Restart the server
|
77
|
+
def restart
|
78
|
+
raise ArgumentError, "Can't restart, no 'on_restart' proc specified" unless @on_restart
|
79
|
+
log '>> Restarting ...'
|
80
|
+
stop
|
81
|
+
remove_pid_file
|
82
|
+
@on_restart.call
|
83
|
+
exit!
|
84
|
+
end
|
85
|
+
|
70
86
|
module ClassMethods
|
71
|
-
#
|
87
|
+
# Send a INT signal the process which PID is stored in +pid_file+.
|
88
|
+
# If the process is still running after +timeout+, KILL signal is
|
89
|
+
# sent.
|
72
90
|
def kill(pid_file, timeout=60)
|
73
|
-
if pid =
|
74
|
-
pid = pid.to_i
|
75
|
-
print "Sending INT signal to process #{pid} ... "
|
91
|
+
if pid = send_signal('INT', pid_file)
|
76
92
|
begin
|
77
|
-
Process.kill('INT', pid)
|
78
93
|
Timeout.timeout(timeout) do
|
79
94
|
sleep 0.1 while Process.running?(pid)
|
80
95
|
end
|
81
96
|
rescue Timeout::Error
|
82
|
-
print "timeout
|
83
|
-
|
97
|
+
print "timeout! "
|
98
|
+
send_signal('KILL', pid_file)
|
84
99
|
end
|
85
|
-
|
100
|
+
end
|
101
|
+
File.delete(pid_file) if File.exist?(pid_file)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Restart the server by sending HUP signal
|
105
|
+
def restart(pid_file)
|
106
|
+
send_signal('HUP', pid_file)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Send a +signal+ to the process which PID is stored in +pid_file+.
|
110
|
+
def send_signal(signal, pid_file)
|
111
|
+
if File.exist?(pid_file) && pid = open(pid_file).read
|
112
|
+
pid = pid.to_i
|
113
|
+
print "Sending #{signal} signal to process #{pid} ... "
|
114
|
+
Process.kill(signal, pid)
|
115
|
+
puts
|
116
|
+
pid
|
86
117
|
else
|
87
|
-
puts "Can't stop process, no PID found in #{
|
118
|
+
puts "Can't stop process, no PID found in #{pid_file}"
|
119
|
+
nil
|
88
120
|
end
|
89
121
|
rescue Errno::ESRCH # No such process
|
90
122
|
puts "process not found!"
|
91
|
-
|
92
|
-
File.delete(pid_file) rescue nil
|
123
|
+
nil
|
93
124
|
end
|
94
125
|
end
|
95
126
|
|
96
|
-
|
97
|
-
def check_plateform_support
|
98
|
-
raise RuntimeError, 'Daemonizing not supported on Windows' if RUBY_PLATFORM =~ /mswin/
|
99
|
-
end
|
100
|
-
|
127
|
+
protected
|
101
128
|
def remove_pid_file
|
102
129
|
File.delete(@pid_file) if @pid_file && File.exists?(@pid_file)
|
103
130
|
end
|
104
|
-
|
131
|
+
|
105
132
|
def write_pid_file
|
106
133
|
log ">> Writing PID to #{@pid_file}"
|
107
134
|
FileUtils.mkdir_p File.dirname(@pid_file)
|