daemons 1.1.9 → 1.2.1

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