daemons 1.1.9 → 1.4.1
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.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +207 -0
- data/Releases +85 -24
- data/examples/call/call.rb +13 -16
- data/examples/call/call_monitor.rb +13 -17
- data/examples/daemonize/daemonize.rb +4 -8
- data/examples/run/ctrl_crash.rb +0 -1
- data/examples/run/ctrl_custom_logfiles.rb +18 -0
- data/examples/run/ctrl_exec.rb +0 -1
- data/examples/run/ctrl_exit.rb +0 -1
- data/examples/run/ctrl_keep_pid_files.rb +1 -3
- data/examples/run/ctrl_monitor.rb +0 -1
- data/examples/run/ctrl_monitor_multiple.rb +17 -0
- data/examples/run/ctrl_monitor_nocrash.rb +15 -0
- data/examples/run/ctrl_multiple.rb +0 -1
- data/examples/run/ctrl_ontop.rb +0 -1
- data/examples/run/ctrl_optionparser.rb +5 -7
- data/examples/run/ctrl_proc.rb +8 -9
- data/examples/run/ctrl_proc_multiple.rb +4 -6
- data/examples/run/ctrl_proc_rand.rb +2 -4
- data/examples/run/ctrl_proc_simple.rb +0 -1
- data/examples/run/myserver.rb +0 -1
- data/examples/run/myserver_crashing.rb +5 -5
- data/examples/run/myserver_exiting.rb +2 -2
- data/examples/run/myserver_hanging.rb +4 -5
- data/examples/run/myserver_slowstop.rb +5 -6
- data/lib/daemons/application.rb +235 -229
- data/lib/daemons/application_group.rb +115 -100
- data/lib/daemons/change_privilege.rb +2 -4
- data/lib/daemons/cmdline.rb +75 -62
- data/lib/daemons/controller.rb +36 -54
- data/lib/daemons/daemonize.rb +74 -75
- data/lib/daemons/etc_extension.rb +3 -4
- data/lib/daemons/exceptions.rb +11 -13
- data/lib/daemons/monitor.rb +57 -77
- data/lib/daemons/pid.rb +26 -56
- data/lib/daemons/pidfile.rb +49 -44
- data/lib/daemons/pidmem.rb +5 -9
- data/lib/daemons/reporter.rb +54 -0
- data/lib/daemons/syslogio.rb +240 -0
- data/lib/daemons/version.rb +3 -0
- data/lib/daemons.rb +87 -77
- metadata +111 -46
- data/README +0 -214
- data/Rakefile +0 -90
- data/TODO +0 -2
- data/setup.rb +0 -1360
data/lib/daemons/application.rb
CHANGED
@@ -2,80 +2,110 @@ require 'daemons/pidfile'
|
|
2
2
|
require 'daemons/pidmem'
|
3
3
|
require 'daemons/change_privilege'
|
4
4
|
require 'daemons/daemonize'
|
5
|
+
require 'daemons/exceptions'
|
6
|
+
require 'daemons/reporter'
|
5
7
|
|
6
8
|
require 'timeout'
|
7
9
|
|
8
|
-
|
9
10
|
module Daemons
|
10
|
-
|
11
11
|
class Application
|
12
|
-
|
13
12
|
attr_accessor :app_argv
|
14
13
|
attr_accessor :controller_argv
|
15
|
-
|
14
|
+
|
16
15
|
# the Pid instance belonging to this application
|
17
16
|
attr_reader :pid
|
18
|
-
|
17
|
+
|
19
18
|
# the ApplicationGroup the application belongs to
|
20
19
|
attr_reader :group
|
21
|
-
|
20
|
+
|
22
21
|
# my private options
|
23
22
|
attr_reader :options
|
24
|
-
|
25
|
-
|
23
|
+
|
26
24
|
SIGNAL = (RUBY_PLATFORM =~ /win32/ ? 'KILL' : 'TERM')
|
27
|
-
|
28
|
-
|
25
|
+
|
29
26
|
def initialize(group, add_options = {}, pid = nil)
|
30
27
|
@group = group
|
31
28
|
@options = group.options.dup
|
32
29
|
@options.update(add_options)
|
33
|
-
|
30
|
+
|
31
|
+
['dir', 'log_dir', 'logfilename', 'output_logfilename'].each do |k|
|
32
|
+
@options[k] = File.expand_path(@options[k]) if @options.key?(k)
|
33
|
+
end
|
34
|
+
|
34
35
|
@dir_mode = @dir = @script = nil
|
35
|
-
|
36
|
+
|
36
37
|
@force_kill_waittime = @options[:force_kill_waittime] || 20
|
37
|
-
|
38
|
+
|
39
|
+
@signals_and_waits = parse_signals_and_waits(@options[:signals_and_waits])
|
40
|
+
|
41
|
+
@show_status_callback = method(:default_show_status)
|
42
|
+
|
43
|
+
@report = Reporter.new(@options)
|
44
|
+
|
38
45
|
unless @pid = pid
|
39
46
|
if @options[:no_pidfiles]
|
40
47
|
@pid = PidMem.new
|
41
48
|
elsif dir = pidfile_dir
|
42
|
-
@pid = PidFile.new(dir, @group.app_name, @group.multiple)
|
49
|
+
@pid = PidFile.new(dir, @group.app_name, @group.multiple, @options[:pid_delimiter])
|
43
50
|
else
|
44
51
|
@pid = PidMem.new
|
45
52
|
end
|
46
53
|
end
|
47
54
|
end
|
48
|
-
|
55
|
+
|
56
|
+
def show_status_callback=(function)
|
57
|
+
@show_status_callback =
|
58
|
+
if function.respond_to?(:call)
|
59
|
+
function
|
60
|
+
else
|
61
|
+
method(function)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
49
65
|
def change_privilege
|
50
66
|
user = options[:user]
|
51
67
|
group = options[:group]
|
52
|
-
|
68
|
+
if user
|
69
|
+
@report.changing_process_privilege(user, group)
|
70
|
+
CurrentProcess.change_privilege(user, group)
|
71
|
+
end
|
53
72
|
end
|
54
|
-
|
73
|
+
|
55
74
|
def script
|
56
|
-
@script
|
75
|
+
@script or group.script
|
57
76
|
end
|
58
|
-
|
77
|
+
|
59
78
|
def pidfile_dir
|
60
|
-
Pid.dir
|
79
|
+
Pid.dir dir_mode, dir, script
|
61
80
|
end
|
62
|
-
|
81
|
+
|
63
82
|
def logdir
|
64
|
-
|
65
|
-
|
66
|
-
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
|
67
|
-
end
|
68
|
-
logdir
|
83
|
+
options[:log_dir] or
|
84
|
+
options[:dir_mode] == :system ? '/var/log' : pidfile_dir
|
69
85
|
end
|
70
|
-
|
86
|
+
|
87
|
+
def output_logfilename
|
88
|
+
options[:output_logfilename] or "#{@group.app_name}.output"
|
89
|
+
end
|
90
|
+
|
71
91
|
def output_logfile
|
72
|
-
|
92
|
+
if log_output_syslog?
|
93
|
+
'SYSLOG'
|
94
|
+
elsif log_output?
|
95
|
+
File.join logdir, output_logfilename
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def logfilename
|
100
|
+
options[:logfilename] or "#{@group.app_name}.log"
|
73
101
|
end
|
74
|
-
|
102
|
+
|
75
103
|
def logfile
|
76
|
-
|
104
|
+
if logdir
|
105
|
+
File.join logdir, logfilename
|
106
|
+
end
|
77
107
|
end
|
78
|
-
|
108
|
+
|
79
109
|
# this function is only used to daemonize the currently running process (Daemons.daemonize)
|
80
110
|
def start_none
|
81
111
|
unless options[:ontop]
|
@@ -83,163 +113,158 @@ module Daemons
|
|
83
113
|
else
|
84
114
|
Daemonize.simulate(output_logfile)
|
85
115
|
end
|
86
|
-
|
116
|
+
|
87
117
|
@pid.pid = Process.pid
|
88
|
-
|
89
|
-
|
118
|
+
|
90
119
|
# We need this to remove the pid-file if the applications exits by itself.
|
91
|
-
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
|
120
|
+
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
|
92
121
|
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
|
93
122
|
# in your application!
|
94
123
|
#
|
95
|
-
at_exit
|
124
|
+
at_exit do
|
96
125
|
begin; @pid.cleanup; rescue ::Exception; end
|
97
|
-
|
126
|
+
|
98
127
|
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
|
99
128
|
# create a exception log.
|
100
|
-
if options[:backtrace]
|
101
|
-
begin; exception_log
|
129
|
+
if options[:backtrace] && !options[:ontop] && !$daemons_sigterm
|
130
|
+
begin; exception_log; rescue ::Exception; end
|
102
131
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
# This part is needed to remove the pid-file if the application is killed by
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
# This part is needed to remove the pid-file if the application is killed by
|
107
136
|
# daemons or manually by the user.
|
108
137
|
# Note that the applications is not supposed to overwrite the signal handler for
|
109
138
|
# 'TERM'.
|
110
139
|
#
|
111
|
-
trap(SIGNAL)
|
140
|
+
trap(SIGNAL) do
|
112
141
|
begin; @pid.cleanup; rescue ::Exception; end
|
113
142
|
$daemons_sigterm = true
|
114
|
-
|
143
|
+
|
115
144
|
if options[:hard_exit]
|
116
145
|
exit!
|
117
146
|
else
|
118
147
|
exit
|
119
148
|
end
|
120
|
-
|
149
|
+
end
|
121
150
|
end
|
122
|
-
|
151
|
+
|
123
152
|
def start_exec
|
124
153
|
if options[:backtrace]
|
125
|
-
|
154
|
+
@report.backtrace_not_supported
|
126
155
|
end
|
127
|
-
|
156
|
+
|
128
157
|
unless options[:ontop]
|
129
158
|
Daemonize.daemonize(output_logfile, @group.app_name)
|
130
159
|
else
|
131
160
|
Daemonize.simulate(output_logfile)
|
132
161
|
end
|
133
|
-
|
162
|
+
|
134
163
|
# note that we cannot remove the pid file if we run in :ontop mode (i.e. 'ruby ctrl_exec.rb run')
|
135
164
|
@pid.pid = Process.pid
|
136
|
-
|
137
|
-
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
Kernel.exec(script(), *(@app_argv || []))
|
165
|
+
|
166
|
+
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
|
167
|
+
|
168
|
+
started
|
169
|
+
Kernel.exec(script, *(@app_argv || []))
|
142
170
|
end
|
143
|
-
|
171
|
+
|
144
172
|
def start_load
|
145
173
|
unless options[:ontop]
|
146
174
|
Daemonize.daemonize(output_logfile, @group.app_name)
|
147
175
|
else
|
148
176
|
Daemonize.simulate(output_logfile)
|
149
177
|
end
|
150
|
-
|
178
|
+
|
151
179
|
@pid.pid = Process.pid
|
152
|
-
|
153
|
-
|
180
|
+
|
154
181
|
# We need this to remove the pid-file if the applications exits by itself.
|
155
|
-
# Note that <tt>at_exit</tt> will only be run if the applications exits by calling
|
182
|
+
# Note that <tt>at_exit</tt> will only be run if the applications exits by calling
|
156
183
|
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
|
157
184
|
# in your application!
|
158
185
|
#
|
159
|
-
at_exit
|
186
|
+
at_exit do
|
160
187
|
begin; @pid.cleanup; rescue ::Exception; end
|
161
|
-
|
188
|
+
|
162
189
|
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
|
163
190
|
# create a exception log.
|
164
|
-
if options[:backtrace]
|
165
|
-
begin; exception_log
|
191
|
+
if options[:backtrace] && !options[:ontop] && !$daemons_sigterm
|
192
|
+
begin; exception_log; rescue ::Exception; end
|
166
193
|
end
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
# This part is needed to remove the pid-file if the application is killed by
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
# This part is needed to remove the pid-file if the application is killed by
|
171
198
|
# daemons or manually by the user.
|
172
199
|
# Note that the applications is not supposed to overwrite the signal handler for
|
173
200
|
# 'TERM'.
|
174
201
|
#
|
175
202
|
$daemons_stop_proc = options[:stop_proc]
|
176
|
-
trap(SIGNAL)
|
203
|
+
trap(SIGNAL) do
|
177
204
|
begin
|
178
|
-
|
179
|
-
|
180
|
-
|
205
|
+
if $daemons_stop_proc
|
206
|
+
$daemons_stop_proc.call
|
207
|
+
end
|
181
208
|
rescue ::Exception
|
182
209
|
end
|
183
|
-
|
210
|
+
|
184
211
|
begin; @pid.cleanup; rescue ::Exception; end
|
185
212
|
$daemons_sigterm = true
|
186
|
-
|
213
|
+
|
187
214
|
if options[:hard_exit]
|
188
215
|
exit!
|
189
216
|
else
|
190
217
|
exit
|
191
218
|
end
|
192
|
-
|
193
|
-
|
219
|
+
end
|
220
|
+
|
194
221
|
# Now we really start the script...
|
195
222
|
$DAEMONS_ARGV = @controller_argv
|
196
223
|
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
|
197
|
-
|
224
|
+
|
198
225
|
ARGV.clear
|
199
226
|
ARGV.concat @app_argv if @app_argv
|
200
|
-
|
201
|
-
started
|
202
|
-
# TODO:
|
203
|
-
load script
|
227
|
+
|
228
|
+
started
|
229
|
+
# TODO: exception logging
|
230
|
+
load script
|
204
231
|
end
|
205
|
-
|
232
|
+
|
206
233
|
def start_proc
|
207
234
|
return unless p = options[:proc]
|
208
|
-
|
209
|
-
myproc = proc do
|
210
|
-
|
211
|
-
@pid.pid = Process.pid
|
212
|
-
|
235
|
+
|
236
|
+
myproc = proc do
|
237
|
+
|
213
238
|
# We need this to remove the pid-file if the applications exits by itself.
|
214
|
-
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
|
239
|
+
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
|
215
240
|
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
|
216
241
|
# in your application!
|
217
242
|
#
|
218
|
-
at_exit
|
243
|
+
at_exit do
|
219
244
|
begin; @pid.cleanup; rescue ::Exception; end
|
220
245
|
|
221
246
|
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
|
222
247
|
# create a exception log.
|
223
|
-
if options[:backtrace]
|
224
|
-
begin; exception_log
|
248
|
+
if options[:backtrace] && !options[:ontop] && !$daemons_sigterm
|
249
|
+
begin; exception_log; rescue ::Exception; end
|
225
250
|
end
|
226
251
|
|
227
|
-
|
252
|
+
end
|
228
253
|
|
229
|
-
# This part is needed to remove the pid-file if the application is killed by
|
254
|
+
# This part is needed to remove the pid-file if the application is killed by
|
230
255
|
# daemons or manually by the user.
|
231
256
|
# Note that the applications is not supposed to overwrite the signal handler for
|
232
257
|
# 'TERM'.
|
233
258
|
#
|
234
259
|
$daemons_stop_proc = options[:stop_proc]
|
235
|
-
trap(SIGNAL)
|
260
|
+
trap(SIGNAL) do
|
236
261
|
begin
|
237
|
-
|
238
|
-
|
239
|
-
|
262
|
+
if $daemons_stop_proc
|
263
|
+
$daemons_stop_proc.call
|
264
|
+
end
|
240
265
|
rescue ::Exception
|
241
266
|
end
|
242
|
-
|
267
|
+
|
243
268
|
begin; @pid.cleanup; rescue ::Exception; end
|
244
269
|
$daemons_sigterm = true
|
245
270
|
|
@@ -248,42 +273,28 @@ module Daemons
|
|
248
273
|
else
|
249
274
|
exit
|
250
275
|
end
|
251
|
-
|
252
|
-
|
253
|
-
started()
|
254
|
-
|
255
|
-
p.call()
|
276
|
+
end
|
277
|
+
p.call
|
256
278
|
end
|
257
|
-
|
279
|
+
|
258
280
|
unless options[:ontop]
|
259
|
-
Daemonize.call_as_daemon(myproc, output_logfile, @group.app_name)
|
260
|
-
|
281
|
+
@pid.pid = Daemonize.call_as_daemon(myproc, output_logfile, @group.app_name)
|
282
|
+
|
261
283
|
else
|
262
284
|
Daemonize.simulate(output_logfile)
|
263
|
-
|
285
|
+
|
264
286
|
myproc.call
|
265
|
-
|
266
|
-
# why did we use this??
|
267
|
-
# Thread.new(&options[:proc])
|
268
|
-
|
269
|
-
# why did we use the code below??
|
270
|
-
# unless pid = Process.fork
|
271
|
-
# @pid.pid = pid
|
272
|
-
# Daemonize.simulate(logfile)
|
273
|
-
# options[:proc].call
|
274
|
-
# exit
|
275
|
-
# else
|
276
|
-
# Process.detach(@pid.pid)
|
277
|
-
# end
|
278
287
|
end
|
279
|
-
|
288
|
+
started
|
280
289
|
end
|
281
|
-
|
282
|
-
|
283
|
-
def start
|
290
|
+
|
291
|
+
def start(restart = false)
|
284
292
|
change_privilege
|
285
|
-
|
286
|
-
|
293
|
+
|
294
|
+
unless restart
|
295
|
+
@group.create_monitor(self) unless options[:ontop] # we don't monitor applications in the foreground
|
296
|
+
end
|
297
|
+
|
287
298
|
case options[:mode]
|
288
299
|
when :none
|
289
300
|
# this is only used to daemonize the currently running process
|
@@ -298,32 +309,14 @@ module Daemons
|
|
298
309
|
start_load
|
299
310
|
end
|
300
311
|
end
|
301
|
-
|
312
|
+
|
302
313
|
def started
|
303
314
|
if pid = @pid.pid
|
304
|
-
|
305
|
-
STDOUT.flush
|
315
|
+
@report.process_started(group.app_name, pid)
|
306
316
|
end
|
307
317
|
end
|
308
|
-
|
309
|
-
|
310
|
-
# def run
|
311
|
-
# if @group.controller.options[:exec]
|
312
|
-
# run_via_exec()
|
313
|
-
# else
|
314
|
-
# run_via_load()
|
315
|
-
# end
|
316
|
-
# end
|
317
|
-
#
|
318
|
-
# def run_via_exec
|
319
|
-
#
|
320
|
-
# end
|
321
|
-
#
|
322
|
-
# def run_via_load
|
323
|
-
#
|
324
|
-
# end
|
325
|
-
|
326
|
-
def reload
|
318
|
+
|
319
|
+
def reload
|
327
320
|
if @pid.pid == 0
|
328
321
|
zap
|
329
322
|
start
|
@@ -342,122 +335,112 @@ module Daemons
|
|
342
335
|
# one cannot catch exceptions that are thrown in threads other than the main
|
343
336
|
# thread.
|
344
337
|
#
|
345
|
-
# This function searches for all exceptions in memory and outputs them to
|
338
|
+
# This function searches for all exceptions in memory and outputs them to $stderr
|
346
339
|
# (if it is connected) and to a log file in the pid-file directory.
|
347
340
|
#
|
348
341
|
def exception_log
|
349
342
|
return unless logfile
|
350
|
-
|
343
|
+
|
351
344
|
require 'logger'
|
352
|
-
|
345
|
+
|
353
346
|
l_file = Logger.new(logfile)
|
354
|
-
|
347
|
+
|
355
348
|
# the code below finds the last exception
|
356
349
|
e = nil
|
357
|
-
|
358
|
-
ObjectSpace.each_object
|
350
|
+
|
351
|
+
ObjectSpace.each_object do |o|
|
359
352
|
if ::Exception === o
|
360
353
|
e = o
|
361
354
|
end
|
362
|
-
|
363
|
-
|
364
|
-
l_file.info
|
355
|
+
end
|
356
|
+
|
357
|
+
l_file.info '*** below you find the most recent exception thrown, this will be likely (but not certainly) the exception that made the application exit abnormally ***'
|
365
358
|
l_file.error e
|
366
|
-
|
367
|
-
l_file.info
|
368
|
-
|
359
|
+
|
360
|
+
l_file.info '*** below you find all exception objects found in memory, some of them may have been thrown in your application, others may just be in memory because they are standard exceptions ***'
|
361
|
+
|
369
362
|
# this code logs every exception found in memory
|
370
|
-
ObjectSpace.each_object
|
363
|
+
ObjectSpace.each_object do |o|
|
371
364
|
if ::Exception === o
|
372
365
|
l_file.error o
|
373
366
|
end
|
374
|
-
|
375
|
-
|
367
|
+
end
|
368
|
+
|
376
369
|
l_file.close
|
377
370
|
end
|
378
|
-
|
379
|
-
|
371
|
+
|
380
372
|
def stop(no_wait = false)
|
381
|
-
|
382
|
-
|
373
|
+
unless running?
|
374
|
+
zap
|
383
375
|
return
|
384
376
|
end
|
385
|
-
|
377
|
+
|
378
|
+
# confusing: pid is also a attribute_reader
|
386
379
|
pid = @pid.pid
|
387
|
-
|
380
|
+
|
388
381
|
# Catch errors when trying to kill a process that doesn't
|
389
382
|
# exist. This happens when the process quits and hasn't been
|
390
383
|
# restarted by the monitor yet. By catching the error, we allow the
|
391
384
|
# pid file clean-up to occur.
|
392
385
|
begin
|
393
|
-
|
386
|
+
wait_and_retry_kill_harder(pid, @signals_and_waits, no_wait)
|
394
387
|
rescue Errno::ESRCH => e
|
395
|
-
|
396
|
-
|
388
|
+
@report.output_message("#{e} #{pid}")
|
389
|
+
@report.output_message('deleting pid-file.')
|
397
390
|
end
|
398
|
-
|
399
|
-
if not no_wait
|
400
|
-
if @force_kill_waittime > 0
|
401
|
-
puts "#{self.group.app_name}: trying to stop process with pid #{pid}..."
|
402
|
-
STDOUT.flush
|
403
|
-
|
404
|
-
begin
|
405
|
-
Timeout::timeout(@force_kill_waittime) {
|
406
|
-
while Pid.running?(pid)
|
407
|
-
sleep(0.2)
|
408
|
-
end
|
409
|
-
}
|
410
|
-
rescue Timeout::Error
|
411
|
-
puts "#{self.group.app_name}: process with pid #{pid} won't stop, we forcefully kill it..."
|
412
|
-
STDOUT.flush
|
413
|
-
|
414
|
-
begin
|
415
|
-
Process.kill('KILL', pid)
|
416
|
-
rescue Errno::ESRCH
|
417
|
-
end
|
418
|
-
|
419
|
-
begin
|
420
|
-
Timeout::timeout(20) {
|
421
|
-
while Pid.running?(pid)
|
422
|
-
sleep(1)
|
423
|
-
end
|
424
|
-
}
|
425
|
-
rescue Timeout::Error
|
426
|
-
puts "#{self.group.app_name}: unable to forcefully kill process with pid #{pid}."
|
427
|
-
STDOUT.flush
|
428
|
-
end
|
429
|
-
end
|
430
|
-
end
|
431
|
-
|
432
|
-
|
433
|
-
end
|
434
|
-
|
391
|
+
|
435
392
|
sleep(0.1)
|
436
393
|
unless Pid.running?(pid)
|
437
394
|
# We try to remove the pid-files by ourselves, in case the application
|
438
395
|
# didn't clean it up.
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
STDOUT.flush
|
396
|
+
zap!
|
397
|
+
|
398
|
+
@report.stopped_process(group.app_name, pid)
|
443
399
|
end
|
444
|
-
|
445
400
|
end
|
446
|
-
|
401
|
+
|
402
|
+
# @param Hash remaing_signals
|
403
|
+
# @param Boolean no_wait Send first Signal and return
|
404
|
+
def wait_and_retry_kill_harder(pid, remaining_signals, no_wait = false)
|
405
|
+
sig_wait = remaining_signals.shift
|
406
|
+
sig = sig_wait[:sig]
|
407
|
+
wait = sig_wait[:wait]
|
408
|
+
Process.kill(sig, pid)
|
409
|
+
return if no_wait || !wait.positive?
|
410
|
+
|
411
|
+
@report.stopping_process(group.app_name, pid, sig, wait)
|
412
|
+
|
413
|
+
begin
|
414
|
+
Timeout.timeout(wait, TimeoutError) do
|
415
|
+
sleep(0.2) while Pid.running?(pid)
|
416
|
+
end
|
417
|
+
rescue TimeoutError
|
418
|
+
if remaining_signals.any?
|
419
|
+
wait_and_retry_kill_harder(pid, remaining_signals)
|
420
|
+
else
|
421
|
+
@report.cannot_stop_process(group.app_name, pid)
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
447
426
|
def zap
|
448
|
-
@pid.
|
427
|
+
@pid.zap
|
449
428
|
end
|
450
|
-
|
429
|
+
|
451
430
|
def zap!
|
452
|
-
begin; @pid.
|
431
|
+
begin; @pid.zap; rescue ::Exception; end
|
453
432
|
end
|
454
|
-
|
433
|
+
|
455
434
|
def show_status
|
456
|
-
|
457
|
-
|
458
|
-
|
435
|
+
@show_status_callback.call(self)
|
436
|
+
end
|
437
|
+
|
438
|
+
def default_show_status(daemon = self)
|
439
|
+
running = daemon.running?
|
440
|
+
|
441
|
+
@report.status(group.app_name, running, daemon.pid.exist?, daemon.pid.pid.to_s)
|
459
442
|
end
|
460
|
-
|
443
|
+
|
461
444
|
# This function implements a (probably too simle) method to detect
|
462
445
|
# whether the program with the pid found in the pid-file is still running.
|
463
446
|
# It just searches for the pid in the output of <tt>ps ax</tt>, which
|
@@ -466,12 +449,35 @@ module Daemons
|
|
466
449
|
# system.
|
467
450
|
#
|
468
451
|
def running?
|
469
|
-
|
470
|
-
|
452
|
+
@pid.exist? and Pid.running? @pid.pid
|
453
|
+
end
|
454
|
+
|
455
|
+
private
|
456
|
+
|
457
|
+
def log_output?
|
458
|
+
options[:log_output] && logdir
|
459
|
+
end
|
460
|
+
|
461
|
+
def log_output_syslog?
|
462
|
+
options[:log_output_syslog]
|
463
|
+
end
|
464
|
+
|
465
|
+
def dir_mode
|
466
|
+
@dir_mode or group.dir_mode
|
467
|
+
end
|
468
|
+
|
469
|
+
def dir
|
470
|
+
@dir or group.dir
|
471
|
+
end
|
472
|
+
|
473
|
+
def parse_signals_and_waits(argv)
|
474
|
+
unless argv
|
475
|
+
return [
|
476
|
+
{ sig: 'TERM', wait: @force_kill_waittime },
|
477
|
+
{ sig: 'KILL', wait: 20 }
|
478
|
+
]
|
471
479
|
end
|
472
|
-
|
473
|
-
return false
|
480
|
+
argv.split('|').collect{ |part| splitted = part.split(':'); {sig: splitted[0], wait: splitted[1].to_i}}
|
474
481
|
end
|
475
482
|
end
|
476
|
-
|
477
483
|
end
|