daemons 1.0.10 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +5 -4
- data/Rakefile +6 -2
- data/Releases +35 -9
- data/TODO +1 -5
- data/examples/run/ctrl_hanging.rb +19 -0
- data/examples/run/myserver.rb +0 -0
- data/examples/run/myserver_hanging.rb +21 -0
- data/lib/daemons/application.rb +111 -15
- data/lib/daemons/application_group.rb +48 -6
- data/lib/daemons/change_privilege.rb +19 -0
- data/lib/daemons/cmdline.rb +8 -1
- data/lib/daemons/controller.rb +9 -3
- data/lib/daemons/daemonize.rb +8 -0
- data/lib/daemons/etc_extension.rb +12 -0
- data/lib/daemons/monitor.rb +12 -1
- data/lib/daemons/pid.rb +9 -1
- data/lib/daemons/pidfile.rb +9 -4
- data/lib/daemons/pidmem.rb +9 -0
- data/lib/daemons.rb +7 -2
- metadata +29 -26
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Daemons Version 1.0
|
1
|
+
= Daemons Version 1.1.0
|
2
2
|
|
3
3
|
(See Releases for release-specific information)
|
4
4
|
|
@@ -19,7 +19,7 @@ process.
|
|
19
19
|
|
20
20
|
== Basic Usage
|
21
21
|
|
22
|
-
You can use Daemons in four
|
22
|
+
You can use Daemons in four different ways:
|
23
23
|
|
24
24
|
=== 1. Create wrapper scripts for your server scripts or applications
|
25
25
|
|
@@ -184,11 +184,12 @@ The RDoc documentation is also online at http://daemons.rubyforge.org
|
|
184
184
|
|
185
185
|
== Author
|
186
186
|
|
187
|
-
Written
|
187
|
+
Written 2005-2010 by Thomas Uehlinger <mailto:th.uehlinger@gmx.ch>.
|
188
|
+
Anonymous SVN checkout is available with "svn checkout http://daemons.rubyforge.org/svn/".
|
188
189
|
|
189
190
|
== License
|
190
191
|
|
191
|
-
Copyright (c) 2005-
|
192
|
+
Copyright (c) 2005-2010 Thomas Uehlinger
|
192
193
|
|
193
194
|
Permission is hereby granted, free of charge, to any person
|
194
195
|
obtaining a copy of this software and associated documentation
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
Gem::manage_gems
|
2
|
+
#Gem::manage_gems
|
3
3
|
|
4
4
|
require 'rake/gempackagetask'
|
5
5
|
#require 'rake/testtask'
|
@@ -68,6 +68,10 @@ end
|
|
68
68
|
|
69
69
|
task :default => [:package]
|
70
70
|
|
71
|
+
desc 'Show information about the gem.'
|
72
|
+
task :debug_gem do
|
73
|
+
puts spec.to_ruby
|
74
|
+
end
|
71
75
|
|
72
76
|
task :upload do
|
73
77
|
sh "scp -r html/* uehli@rubyforge.org:/var/www/gforge-projects/daemons"
|
@@ -81,4 +85,4 @@ rd = Rake::RDocTask.new("rdoc") { |rdoc|
|
|
81
85
|
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
|
82
86
|
rdoc.rdoc_files.include('README', 'TODO', 'Releases')
|
83
87
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
84
|
-
}
|
88
|
+
}
|
data/Releases
CHANGED
@@ -1,26 +1,51 @@
|
|
1
1
|
= Daemons Release History
|
2
2
|
|
3
|
-
== Release 1.0
|
3
|
+
== Release 1.1.0: June 20, 2010
|
4
|
+
|
5
|
+
* Honour the options[:app_name] in Daemons.daemonize (thanks to Ryan Tecco).
|
6
|
+
* Included a new option :stop_proc to specify a proc that will be called when a
|
7
|
+
daemonized process receives a request to stop (thanks to Dave Dupre).
|
8
|
+
* Only delete the pidfile if the current pid is the original pid (ghazel).
|
9
|
+
* Start when restart but no application running (pcreux).
|
10
|
+
* Silently continue if there is no pidfile (ghazel).
|
11
|
+
* We now per default wait for processes to stop and
|
12
|
+
kill them automatically it if they do not stop within a given time
|
13
|
+
(force_kill_waittime). Use the option --no_wait to not wait for processes to
|
14
|
+
stop.
|
15
|
+
* Set log files mode to 0644 (mikehale).
|
16
|
+
* Set pid file permissions to 0644 (mikehale).
|
17
|
+
* Added ability to change process uid/gid (mikehale).
|
18
|
+
* Fix for: If you happen to start a daemon from a process that has open file
|
19
|
+
descriptors these will stay open. As it is daemonize.rb only closes ruby IO
|
20
|
+
objects (thanks to Han Holl).
|
21
|
+
* New reload command (SIGHUP) (thanks to Michael Schuerig).
|
22
|
+
|
23
|
+
== Release 1.0.10: March 21, 2008
|
4
24
|
|
5
25
|
* By default, we now delete stray pid-files (i.e. pid-files which result for
|
6
|
-
example from a killed daemon) automatically. This function can be deactivated
|
7
|
-
passing :keep_pid_files => true as an option.
|
8
|
-
* All pid files of :multiple daemons new get deleted correctly upon exit of the
|
26
|
+
example from a killed daemon) automatically. This function can be deactivated
|
27
|
+
by passing :keep_pid_files => true as an option.
|
28
|
+
* All pid files of :multiple daemons new get deleted correctly upon exit of the
|
29
|
+
daemons (reported by Han Holl).
|
9
30
|
* Use the signal 'KILL' instead of 'TERM' on Windows platforms.
|
10
|
-
* Use exit! in trap('TERM') instead of exit when option :hard_exit is given
|
31
|
+
* Use exit! in trap('TERM') instead of exit when option :hard_exit is given
|
32
|
+
(thanks to Han Holl).
|
11
33
|
* Did some clarification on the exception log.
|
12
34
|
|
13
35
|
== Release 1.0.9: October 29, 2007
|
14
36
|
|
15
|
-
* fixed a severe bug in the new Pid.running? function: function returned true if
|
37
|
+
* fixed a severe bug in the new Pid.running? function: function returned true if
|
38
|
+
the process did not exist (thanks to Jeremy Lawler).
|
16
39
|
|
17
40
|
== Release 1.0.8: September 24, 2007
|
18
41
|
|
19
|
-
* new Pid.running? function. Checking whether a process exists by sending
|
42
|
+
* new Pid.running? function. Checking whether a process exists by sending
|
43
|
+
signal '0' (thanks to Dru Nelson).
|
20
44
|
|
21
45
|
== Release 1.0.7: July 7, 2007
|
22
46
|
|
23
|
-
* Patch to fix wrong ARGV when using :exec (in def start_exec:
|
47
|
+
* Patch to fix wrong ARGV when using :exec (in def start_exec:
|
48
|
+
Kernel.exec(script(), *(@app_argv || []))) (thanks to Alex McGuire).
|
24
49
|
|
25
50
|
== Release 1.0.6: Mai 8, 2007
|
26
51
|
|
@@ -37,7 +62,8 @@
|
|
37
62
|
|
38
63
|
* Document the :log_output option (thanks to Andrew Kuklewicz).
|
39
64
|
* Set STDOUT.sync = true when redirecting to a logfile (thanks to Andrew Kuklewicz).
|
40
|
-
* Should now run also correctly when there is no working 'ps ax' on the system
|
65
|
+
* Should now run also correctly when there is no working 'ps ax' on the system
|
66
|
+
(thanks to Daniel Kehoe).
|
41
67
|
|
42
68
|
== Release 1.0.3: November 1, 2006
|
43
69
|
|
data/TODO
CHANGED
@@ -1,6 +1,2 @@
|
|
1
|
-
*
|
2
|
-
* write some real tests (2005-02-08)
|
3
|
-
* document the new options (2005-03-14) *DONE*
|
4
|
-
* start/stop with --force options (2005-04-05)
|
5
|
-
* option to give some console output on start/stop commands (2005-04-05)
|
1
|
+
* put TODOS here
|
6
2
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '../../lib'))
|
2
|
+
|
3
|
+
if File.exist?(File.join(lib_dir, 'daemons.rb'))
|
4
|
+
$LOAD_PATH.unshift lib_dir
|
5
|
+
else
|
6
|
+
begin; require 'rubygems'; rescue ::Exception; end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'daemons'
|
10
|
+
|
11
|
+
options = {
|
12
|
+
#:mode => :exec,
|
13
|
+
:multiple => true,
|
14
|
+
:no_pidfiles => true,
|
15
|
+
:force_kill_waittime => 5
|
16
|
+
#:force_kill_waittime => -1 # do not wait before killing -9
|
17
|
+
}
|
18
|
+
|
19
|
+
Daemons.run(File.join(File.dirname(__FILE__), 'myserver_hanging.rb'), options)
|
data/examples/run/myserver.rb
CHANGED
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
|
4
|
+
# This is myserver.rb, an example server that is to be controlled by daemons
|
5
|
+
# and that does nothing really useful at the moment.
|
6
|
+
#
|
7
|
+
# Don't run this script by yourself, it can be controlled by the ctrl*.rb scripts.
|
8
|
+
|
9
|
+
trap('TERM') {
|
10
|
+
puts "received TERM"
|
11
|
+
|
12
|
+
loop do
|
13
|
+
puts 'hanging!'
|
14
|
+
sleep(3)
|
15
|
+
end
|
16
|
+
}
|
17
|
+
|
18
|
+
loop do
|
19
|
+
puts 'ping from myserver.rb!'
|
20
|
+
sleep(3)
|
21
|
+
end
|
data/lib/daemons/application.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'daemons/pidfile'
|
2
2
|
require 'daemons/pidmem'
|
3
|
+
require 'daemons/change_privilege'
|
4
|
+
|
5
|
+
require 'timeout'
|
3
6
|
|
4
7
|
|
5
8
|
module Daemons
|
@@ -29,8 +32,12 @@ module Daemons
|
|
29
32
|
|
30
33
|
@dir_mode = @dir = @script = nil
|
31
34
|
|
35
|
+
@force_kill_waittime = @options[:force_kill_waittime] || 20
|
36
|
+
|
32
37
|
unless @pid = pid
|
33
|
-
if
|
38
|
+
if @options[:no_pidfiles]
|
39
|
+
@pid = PidMem.new
|
40
|
+
elsif dir = pidfile_dir
|
34
41
|
@pid = PidFile.new(dir, @group.app_name, @group.multiple)
|
35
42
|
else
|
36
43
|
@pid = PidMem.new
|
@@ -38,6 +45,12 @@ module Daemons
|
|
38
45
|
end
|
39
46
|
end
|
40
47
|
|
48
|
+
def change_privilege
|
49
|
+
user = options[:user]
|
50
|
+
group = options[:group]
|
51
|
+
CurrentProcess.change_privilege(user, group) if user
|
52
|
+
end
|
53
|
+
|
41
54
|
def script
|
42
55
|
@script || @group.script
|
43
56
|
end
|
@@ -46,13 +59,19 @@ module Daemons
|
|
46
59
|
Pid.dir(@dir_mode || @group.dir_mode, @dir || @group.dir, @script || @group.script)
|
47
60
|
end
|
48
61
|
|
62
|
+
def logdir
|
63
|
+
logdir = options[:log_dir]
|
64
|
+
unless logdir
|
65
|
+
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
|
66
|
+
end
|
67
|
+
logdir
|
68
|
+
end
|
69
|
+
|
49
70
|
def output_logfile
|
50
|
-
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
|
51
71
|
(options[:log_output] && logdir) ? File.join(logdir, @group.app_name + '.output') : nil
|
52
72
|
end
|
53
73
|
|
54
74
|
def logfile
|
55
|
-
logdir = options[:dir_mode] == :system ? '/var/log' : pidfile_dir
|
56
75
|
logdir ? File.join(logdir, @group.app_name + '.log') : nil
|
57
76
|
end
|
58
77
|
|
@@ -113,12 +132,11 @@ module Daemons
|
|
113
132
|
|
114
133
|
# note that we cannot remove the pid file if we run in :ontop mode (i.e. 'ruby ctrl_exec.rb run')
|
115
134
|
@pid.pid = Process.pid
|
116
|
-
|
135
|
+
|
117
136
|
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
|
118
137
|
# haven't tested yet if this is really passed to the exec'd process...
|
119
138
|
|
120
|
-
|
121
|
-
|
139
|
+
started()
|
122
140
|
Kernel.exec(script(), *(@app_argv || []))
|
123
141
|
#Kernel.exec(script(), *ARGV)
|
124
142
|
end
|
@@ -134,7 +152,7 @@ module Daemons
|
|
134
152
|
|
135
153
|
|
136
154
|
# We need this to remove the pid-file if the applications exits by itself.
|
137
|
-
# Note that <tt>
|
155
|
+
# Note that <tt>at_exit</tt> will only be run if the applications exits by calling
|
138
156
|
# <tt>exit</tt>, and not if it calls <tt>exit!</tt> (so please don't call <tt>exit!</tt>
|
139
157
|
# in your application!
|
140
158
|
#
|
@@ -154,7 +172,15 @@ module Daemons
|
|
154
172
|
# Note that the applications is not supposed to overwrite the signal handler for
|
155
173
|
# 'TERM'.
|
156
174
|
#
|
175
|
+
$daemons_stop_proc = options[:stop_proc]
|
157
176
|
trap(SIGNAL) {
|
177
|
+
begin
|
178
|
+
if $daemons_stop_proc
|
179
|
+
$daemons_stop_proc.call
|
180
|
+
end
|
181
|
+
rescue ::Exception
|
182
|
+
end
|
183
|
+
|
158
184
|
begin; @pid.cleanup; rescue ::Exception; end
|
159
185
|
$daemons_sigterm = true
|
160
186
|
|
@@ -172,6 +198,7 @@ module Daemons
|
|
172
198
|
ARGV.clear
|
173
199
|
ARGV.concat @app_argv if @app_argv
|
174
200
|
|
201
|
+
started()
|
175
202
|
# TODO: begin - rescue - end around this and exception logging
|
176
203
|
load script()
|
177
204
|
end
|
@@ -201,7 +228,15 @@ module Daemons
|
|
201
228
|
# Note that the applications is not supposed to overwrite the signal handler for
|
202
229
|
# 'TERM'.
|
203
230
|
#
|
231
|
+
$daemons_stop_proc = options[:stop_proc]
|
204
232
|
trap(SIGNAL) {
|
233
|
+
begin
|
234
|
+
if $daemons_stop_proc
|
235
|
+
$daemons_stop_proc.call
|
236
|
+
end
|
237
|
+
rescue ::Exception
|
238
|
+
end
|
239
|
+
|
205
240
|
begin; @pid.cleanup; rescue ::Exception; end
|
206
241
|
$daemons_sigterm = true
|
207
242
|
|
@@ -217,6 +252,7 @@ module Daemons
|
|
217
252
|
|
218
253
|
unless options[:ontop]
|
219
254
|
@pid.pid = Daemonize.call_as_daemon(myproc, output_logfile, @group.app_name)
|
255
|
+
|
220
256
|
else
|
221
257
|
Daemonize.simulate(output_logfile)
|
222
258
|
|
@@ -237,10 +273,13 @@ module Daemons
|
|
237
273
|
# Process.detach(@pid.pid)
|
238
274
|
# end
|
239
275
|
end
|
276
|
+
|
277
|
+
started()
|
240
278
|
end
|
241
279
|
|
242
280
|
|
243
281
|
def start
|
282
|
+
change_privilege
|
244
283
|
@group.create_monitor(@group.applications[0] || self) unless options[:ontop] # we don't monitor applications in the foreground
|
245
284
|
|
246
285
|
case options[:mode]
|
@@ -258,6 +297,14 @@ module Daemons
|
|
258
297
|
end
|
259
298
|
end
|
260
299
|
|
300
|
+
def started
|
301
|
+
if pid = @pid.pid
|
302
|
+
puts "#{self.group.app_name}: process with pid #{pid} started."
|
303
|
+
STDOUT.flush
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
|
261
308
|
# def run
|
262
309
|
# if @group.controller.options[:exec]
|
263
310
|
# run_via_exec()
|
@@ -274,6 +321,11 @@ module Daemons
|
|
274
321
|
#
|
275
322
|
# end
|
276
323
|
|
324
|
+
def reload
|
325
|
+
Process.kill('HUP', @pid.pid)
|
326
|
+
rescue
|
327
|
+
# ignore
|
328
|
+
end
|
277
329
|
|
278
330
|
# This is a nice little function for debugging purposes:
|
279
331
|
# In case a multi-threaded ruby script exits due to an uncaught exception
|
@@ -316,26 +368,70 @@ module Daemons
|
|
316
368
|
end
|
317
369
|
|
318
370
|
|
319
|
-
def stop
|
320
|
-
if
|
371
|
+
def stop(no_wait = false)
|
372
|
+
if not running?
|
321
373
|
self.zap
|
322
374
|
return
|
323
375
|
end
|
324
376
|
|
377
|
+
pid = @pid.pid
|
378
|
+
|
325
379
|
# Catch errors when trying to kill a process that doesn't
|
326
380
|
# exist. This happens when the process quits and hasn't been
|
327
381
|
# restarted by the monitor yet. By catching the error, we allow the
|
328
382
|
# pid file clean-up to occur.
|
329
383
|
begin
|
330
|
-
Process.kill(SIGNAL,
|
384
|
+
Process.kill(SIGNAL, pid)
|
331
385
|
rescue Errno::ESRCH => e
|
332
|
-
puts "#{e} #{
|
386
|
+
puts "#{e} #{pid}"
|
333
387
|
puts "deleting pid-file."
|
334
388
|
end
|
335
389
|
|
336
|
-
|
337
|
-
|
338
|
-
|
390
|
+
if not no_wait
|
391
|
+
if @force_kill_waittime > 0
|
392
|
+
puts "#{self.group.app_name}: trying to stop process with pid #{pid}..."
|
393
|
+
STDOUT.flush
|
394
|
+
|
395
|
+
begin
|
396
|
+
Timeout::timeout(@force_kill_waittime) {
|
397
|
+
while @pid.running?
|
398
|
+
sleep(0.2)
|
399
|
+
end
|
400
|
+
}
|
401
|
+
rescue Timeout::Error
|
402
|
+
puts "#{self.group.app_name}: process with pid #{pid} won't stop, we forcefully kill it..."
|
403
|
+
STDOUT.flush
|
404
|
+
|
405
|
+
begin
|
406
|
+
Process.kill('KILL', pid)
|
407
|
+
rescue Errno::ESRCH
|
408
|
+
end
|
409
|
+
|
410
|
+
begin
|
411
|
+
Timeout::timeout(20) {
|
412
|
+
while @pid.running?
|
413
|
+
sleep(1)
|
414
|
+
end
|
415
|
+
}
|
416
|
+
rescue Timeout::Error
|
417
|
+
puts "#{self.group.app_name}: unable to forcefully kill process with pid #{pid}."
|
418
|
+
STDOUT.flush
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
sleep(0.1)
|
427
|
+
unless @pid.running?
|
428
|
+
# We try to remove the pid-files by ourselves, in case the application
|
429
|
+
# didn't clean it up.
|
430
|
+
begin; @pid.cleanup; rescue ::Exception; end
|
431
|
+
|
432
|
+
puts "#{self.group.app_name}: process with pid #{pid} successfully stopped."
|
433
|
+
STDOUT.flush
|
434
|
+
end
|
339
435
|
|
340
436
|
end
|
341
437
|
|
@@ -369,4 +465,4 @@ module Daemons
|
|
369
465
|
end
|
370
466
|
end
|
371
467
|
|
372
|
-
end
|
468
|
+
end
|
@@ -42,6 +42,7 @@ module Daemons
|
|
42
42
|
@dir = options[:dir] || ''
|
43
43
|
|
44
44
|
@keep_pid_files = options[:keep_pid_files] || false
|
45
|
+
@no_pidfiles = options[:no_pidfiles] || false
|
45
46
|
|
46
47
|
#@applications = find_applications(pidfile_dir())
|
47
48
|
@applications = []
|
@@ -60,6 +61,41 @@ module Daemons
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def find_applications(dir)
|
64
|
+
if @no_pidfiles
|
65
|
+
return find_applications_by_app_name(app_name)
|
66
|
+
else
|
67
|
+
return find_applications_by_pidfiles(dir)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: identifiy the monitor process
|
72
|
+
def find_applications_by_app_name(app_name)
|
73
|
+
pids = []
|
74
|
+
|
75
|
+
begin
|
76
|
+
x = `ps auxw | grep -v grep | awk '{print $2, $11, $12}' | grep #{app_name}`
|
77
|
+
if x && x.chomp!
|
78
|
+
processes = x.split(/\n/).compact
|
79
|
+
processes = processes.delete_if do |p|
|
80
|
+
pid, name, add = p.split(/\s/)
|
81
|
+
# We want to make sure that the first part of the process name matches
|
82
|
+
# so that app_name matches app_name_22
|
83
|
+
|
84
|
+
app_name != name[0..(app_name.length - 1)] and not add.include?(app_name)
|
85
|
+
end
|
86
|
+
pids = processes.map {|p| p.split(/\s/)[0].to_i}
|
87
|
+
end
|
88
|
+
rescue ::Exception
|
89
|
+
end
|
90
|
+
|
91
|
+
return pids.map {|f|
|
92
|
+
app = Application.new(self, {}, PidMem.existing(f))
|
93
|
+
setup_app(app)
|
94
|
+
app
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def find_applications_by_pidfiles(dir)
|
63
99
|
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
|
64
100
|
|
65
101
|
#pp pid_files
|
@@ -125,18 +161,24 @@ module Daemons
|
|
125
161
|
}
|
126
162
|
end
|
127
163
|
|
128
|
-
def stop_all(
|
164
|
+
def stop_all(no_wait = false)
|
129
165
|
@monitor.stop if @monitor
|
130
166
|
|
167
|
+
threads = []
|
168
|
+
|
131
169
|
@applications.each {|a|
|
132
|
-
|
133
|
-
|
134
|
-
else
|
135
|
-
a.stop
|
170
|
+
threads << Thread.new do
|
171
|
+
a.stop(no_wait)
|
136
172
|
end
|
137
173
|
}
|
174
|
+
|
175
|
+
threads.each {|t| t.join}
|
138
176
|
end
|
139
177
|
|
178
|
+
def reload_all
|
179
|
+
@applications.each {|a| a.reload}
|
180
|
+
end
|
181
|
+
|
140
182
|
def zap_all
|
141
183
|
@monitor.stop if @monitor
|
142
184
|
|
@@ -149,4 +191,4 @@ module Daemons
|
|
149
191
|
|
150
192
|
end
|
151
193
|
|
152
|
-
end
|
194
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'daemons/etc_extension'
|
2
|
+
|
3
|
+
class CurrentProcess
|
4
|
+
def self.change_privilege(user, group=user)
|
5
|
+
puts "Changing process privilege to #{user}:#{group}"
|
6
|
+
|
7
|
+
uid, gid = Process.euid, Process.egid
|
8
|
+
target_uid = Etc.getpwnam(user).uid
|
9
|
+
target_gid = Etc.getgrnam(group).gid
|
10
|
+
|
11
|
+
if uid != target_uid || gid != target_gid
|
12
|
+
Process.initgroups(user, target_gid)
|
13
|
+
Process::GID.change_privilege(target_gid)
|
14
|
+
Process::UID.change_privilege(target_uid)
|
15
|
+
end
|
16
|
+
rescue Errno::EPERM => e
|
17
|
+
raise "Couldn't change user and group to #{user}:#{group}: #{e}"
|
18
|
+
end
|
19
|
+
end
|
data/lib/daemons/cmdline.rb
CHANGED
@@ -26,6 +26,10 @@ module Daemons
|
|
26
26
|
@options[:force] = t
|
27
27
|
end
|
28
28
|
|
29
|
+
opts.on("-n", "--no_wait", "Do not wait for processes to stop") do |t|
|
30
|
+
@options[:no_wait] = t
|
31
|
+
end
|
32
|
+
|
29
33
|
#opts.separator ""
|
30
34
|
#opts.separator "Specific options:"
|
31
35
|
|
@@ -56,6 +60,7 @@ module Daemons
|
|
56
60
|
@usage = <<END
|
57
61
|
-t, --ontop Stay on top (does not daemonize)
|
58
62
|
-f, --force Force operation
|
63
|
+
-n, --no_wait Do not wait for processes to stop
|
59
64
|
|
60
65
|
Common options:
|
61
66
|
-h, --help Show this message
|
@@ -92,8 +97,10 @@ END
|
|
92
97
|
puts " start start an instance of the application"
|
93
98
|
puts " stop stop all instances of the application"
|
94
99
|
puts " restart stop all instances and restart them afterwards"
|
100
|
+
puts " reload send a SIGHUP to all instances of the application"
|
95
101
|
puts " run start the application and stay on top"
|
96
102
|
puts " zap set the application to a stopped state"
|
103
|
+
puts " status show status (PID) of application instances"
|
97
104
|
puts
|
98
105
|
puts "* and where <options> may contain several of the following:"
|
99
106
|
|
@@ -114,4 +121,4 @@ END
|
|
114
121
|
|
115
122
|
end
|
116
123
|
|
117
|
-
end
|
124
|
+
end
|
data/lib/daemons/controller.rb
CHANGED
@@ -15,6 +15,7 @@ module Daemons
|
|
15
15
|
'restart',
|
16
16
|
'run',
|
17
17
|
'zap',
|
18
|
+
'reload',
|
18
19
|
'status'
|
19
20
|
]
|
20
21
|
|
@@ -71,13 +72,18 @@ module Daemons
|
|
71
72
|
@options[:ontop] ||= true
|
72
73
|
@group.new_application.start
|
73
74
|
when 'stop'
|
74
|
-
@group.stop_all
|
75
|
+
@group.stop_all(@options[:no_wait])
|
75
76
|
when 'restart'
|
76
77
|
unless @group.applications.empty?
|
77
78
|
@group.stop_all
|
78
|
-
sleep
|
79
|
+
sleep(1)
|
79
80
|
@group.start_all
|
81
|
+
else
|
82
|
+
puts "Warning: no instances running. Starting..."
|
83
|
+
@group.new_application.start
|
80
84
|
end
|
85
|
+
when 'reload'
|
86
|
+
@group.reload_all
|
81
87
|
when 'zap'
|
82
88
|
@group.zap_all
|
83
89
|
when 'status'
|
@@ -131,4 +137,4 @@ module Daemons
|
|
131
137
|
end
|
132
138
|
end
|
133
139
|
|
134
|
-
end
|
140
|
+
end
|
data/lib/daemons/daemonize.rb
CHANGED
@@ -186,6 +186,13 @@ module Daemonize
|
|
186
186
|
end
|
187
187
|
end
|
188
188
|
end
|
189
|
+
|
190
|
+
ios = Array.new(8192){|i| IO.for_fd(i) rescue nil}.compact
|
191
|
+
ios.each do |io|
|
192
|
+
next if io.fileno < 3
|
193
|
+
io.close
|
194
|
+
end
|
195
|
+
|
189
196
|
|
190
197
|
redirect_io(logfile_name)
|
191
198
|
|
@@ -247,6 +254,7 @@ module Daemonize
|
|
247
254
|
if logfile_name
|
248
255
|
begin
|
249
256
|
STDOUT.reopen logfile_name, "a"
|
257
|
+
File.chmod(0644, logfile_name)
|
250
258
|
STDOUT.sync = true
|
251
259
|
rescue ::Exception
|
252
260
|
begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
|
data/lib/daemons/monitor.rb
CHANGED
@@ -116,7 +116,18 @@ module Daemons
|
|
116
116
|
|
117
117
|
|
118
118
|
def stop
|
119
|
-
begin
|
119
|
+
begin
|
120
|
+
pid = @pid.pid
|
121
|
+
Process.kill(Application::SIGNAL, pid)
|
122
|
+
Timeout::timeout(5) {
|
123
|
+
while Pid.running?(pid)
|
124
|
+
sleep(0.1)
|
125
|
+
end
|
126
|
+
}
|
127
|
+
rescue ::Exception => e
|
128
|
+
puts "#{e} #{pid}"
|
129
|
+
puts "deleting pid-file."
|
130
|
+
end
|
120
131
|
|
121
132
|
# We try to remove the pid-files by ourselves, in case the application
|
122
133
|
# didn't clean it up.
|
data/lib/daemons/pid.rb
CHANGED
@@ -6,6 +6,8 @@ module Daemons
|
|
6
6
|
class Pid
|
7
7
|
|
8
8
|
def Pid.running?(pid)
|
9
|
+
return false unless pid
|
10
|
+
|
9
11
|
# Check if process is in existence
|
10
12
|
# The simplest way to do this is to send signal '0'
|
11
13
|
# (which is a single system call) that doesn't actually
|
@@ -49,6 +51,7 @@ module Daemons
|
|
49
51
|
# end
|
50
52
|
|
51
53
|
|
54
|
+
|
52
55
|
# Returns the directory that should be used to write the pid file to
|
53
56
|
# depending on the given mode.
|
54
57
|
#
|
@@ -86,11 +89,16 @@ module Daemons
|
|
86
89
|
def pid=(p)
|
87
90
|
end
|
88
91
|
|
92
|
+
# Check whether the process is running
|
93
|
+
def running?
|
94
|
+
return Pid.running?(pid())
|
95
|
+
end
|
96
|
+
|
89
97
|
# Cleanup method
|
90
98
|
def cleanup
|
91
99
|
end
|
92
100
|
|
93
|
-
#
|
101
|
+
# Exist? method
|
94
102
|
def exist?
|
95
103
|
true
|
96
104
|
end
|
data/lib/daemons/pidfile.rb
CHANGED
@@ -92,18 +92,23 @@ module Daemons
|
|
92
92
|
|
93
93
|
def pid=(p)
|
94
94
|
File.open(filename, 'w') {|f|
|
95
|
+
f.chmod(0644)
|
95
96
|
f.puts p #Process.pid
|
96
97
|
}
|
97
98
|
end
|
98
99
|
|
99
100
|
def cleanup
|
100
|
-
File.delete(filename)
|
101
|
+
File.delete(filename) if pid == Process.pid
|
101
102
|
end
|
102
103
|
|
103
104
|
def pid
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
begin
|
106
|
+
File.open(filename) {|f|
|
107
|
+
return f.gets.to_i
|
108
|
+
}
|
109
|
+
rescue ::Exception
|
110
|
+
return nil
|
111
|
+
end
|
107
112
|
end
|
108
113
|
|
109
114
|
end
|
data/lib/daemons/pidmem.rb
CHANGED
data/lib/daemons.rb
CHANGED
@@ -12,6 +12,7 @@ require 'daemons/application'
|
|
12
12
|
require 'daemons/application_group'
|
13
13
|
require 'daemons/controller'
|
14
14
|
|
15
|
+
require 'timeout'
|
15
16
|
|
16
17
|
# All functions and classes that Daemons provides reside in this module.
|
17
18
|
#
|
@@ -65,7 +66,7 @@ require 'daemons/controller'
|
|
65
66
|
#
|
66
67
|
module Daemons
|
67
68
|
|
68
|
-
VERSION = "1.0
|
69
|
+
VERSION = "1.1.0"
|
69
70
|
|
70
71
|
require 'daemons/daemonize'
|
71
72
|
|
@@ -106,6 +107,7 @@ module Daemons
|
|
106
107
|
# <tt>:ontop</tt>:: When given (i.e. set to true), stay on top, i.e. do not daemonize the application
|
107
108
|
# (but the pid-file and other things are written as usual)
|
108
109
|
# <tt>:mode</tt>:: <tt>:load</tt> Load the script with <tt>Kernel.load</tt>;
|
110
|
+
# note that :stop_proc only works for the :load (and :proc) mode.
|
109
111
|
# <tt>:exec</tt> Execute the script file with <tt>Kernel.exec</tt>
|
110
112
|
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
|
111
113
|
# pid-file directory if the application exits due to an uncaught exception
|
@@ -114,6 +116,8 @@ module Daemons
|
|
114
116
|
# <tt>:keep_pid_files</tt>:: When given do not delete lingering pid-files (files for which the process is no longer running).
|
115
117
|
# <tt>:hard_exit</tt>:: When given use exit! to end a daemons instead of exit (this will for example
|
116
118
|
# not call at_exit handlers).
|
119
|
+
# <tt>:stop_proc</tt>:: A proc that will be called when the daemonized process receives a request to stop (works only for :load and :proc mode)
|
120
|
+
#
|
117
121
|
# -----
|
118
122
|
#
|
119
123
|
# === Example:
|
@@ -158,6 +162,7 @@ module Daemons
|
|
158
162
|
# +options+:: A hash that may contain one or more of the options listed in the documentation for Daemons.run
|
159
163
|
#
|
160
164
|
# A block must be given to this function. The block will be used as the :proc entry in the options hash.
|
165
|
+
#
|
161
166
|
# -----
|
162
167
|
#
|
163
168
|
# === Example:
|
@@ -267,7 +272,7 @@ module Daemons
|
|
267
272
|
# }
|
268
273
|
#
|
269
274
|
def daemonize(options = {})
|
270
|
-
@group ||= ApplicationGroup.new('self', options)
|
275
|
+
@group ||= ApplicationGroup.new(options[:app_name] || 'self', options)
|
271
276
|
|
272
277
|
@group.new_application(:mode => :none).start
|
273
278
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: daemons
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Uehlinger
|
@@ -9,11 +9,11 @@ autorequire: daemons
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-06-20 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server)
|
16
|
+
description: " Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server) \n to be run as a daemon and to be controlled by simple start/stop/restart commands.\n \n You can also call blocks as daemons and control them from the parent or just daemonize the current\n process.\n \n Besides this basic functionality, daemons offers many advanced features like exception \n backtracing and logging (in case your ruby script crashes) and monitoring and automatic\n restarting of your processes if they crash.\n"
|
17
17
|
email: th.uehlinger@gmx.ch
|
18
18
|
executables: []
|
19
19
|
|
@@ -30,43 +30,46 @@ files:
|
|
30
30
|
- README
|
31
31
|
- LICENSE
|
32
32
|
- setup.rb
|
33
|
-
- lib/daemons
|
33
|
+
- lib/daemons.rb
|
34
|
+
- lib/daemons/monitor.rb
|
34
35
|
- lib/daemons/application_group.rb
|
36
|
+
- lib/daemons/etc_extension.rb
|
37
|
+
- lib/daemons/daemonize.rb
|
35
38
|
- lib/daemons/cmdline.rb
|
36
39
|
- lib/daemons/controller.rb
|
37
|
-
- lib/daemons/
|
38
|
-
- lib/daemons/
|
39
|
-
- lib/daemons/
|
40
|
+
- lib/daemons/change_privilege.rb
|
41
|
+
- lib/daemons/application.rb
|
42
|
+
- lib/daemons/pidmem.rb
|
40
43
|
- lib/daemons/pid.rb
|
41
44
|
- lib/daemons/pidfile.rb
|
42
|
-
- lib/daemons/
|
43
|
-
- lib/daemons.rb
|
44
|
-
- examples/call
|
45
|
+
- lib/daemons/exceptions.rb
|
45
46
|
- examples/call/call.rb
|
46
47
|
- examples/call/call_monitor.rb
|
47
|
-
- examples/
|
48
|
-
- examples/daemonize/daemonize.rb
|
49
|
-
- examples/run
|
50
|
-
- examples/run/ctrl_crash.rb
|
51
|
-
- examples/run/ctrl_exec.rb
|
52
|
-
- examples/run/ctrl_exit.rb
|
53
|
-
- examples/run/ctrl_keep_pid_files.rb
|
48
|
+
- examples/run/ctrl_normal.rb
|
54
49
|
- examples/run/ctrl_monitor.rb
|
50
|
+
- examples/run/ctrl_proc.rb
|
55
51
|
- examples/run/ctrl_multiple.rb
|
56
|
-
- examples/run/ctrl_normal.rb
|
57
|
-
- examples/run/ctrl_ontop.rb
|
58
52
|
- examples/run/ctrl_optionparser.rb
|
59
|
-
- examples/run/ctrl_proc.rb
|
60
|
-
- examples/run/ctrl_proc.rb.output
|
61
|
-
- examples/run/ctrl_proc_multiple.rb
|
62
|
-
- examples/run/ctrl_proc_multiple.rb.output
|
63
|
-
- examples/run/ctrl_proc_simple.rb
|
64
53
|
- examples/run/myserver.rb
|
54
|
+
- examples/run/myserver_hanging.rb
|
55
|
+
- examples/run/ctrl_exit.rb
|
65
56
|
- examples/run/myserver_crashing.rb
|
57
|
+
- examples/run/ctrl_proc_multiple.rb
|
58
|
+
- examples/run/ctrl_proc.rb.output
|
59
|
+
- examples/run/ctrl_keep_pid_files.rb
|
60
|
+
- examples/run/ctrl_proc_simple.rb
|
61
|
+
- examples/run/ctrl_ontop.rb
|
62
|
+
- examples/run/ctrl_crash.rb
|
63
|
+
- examples/run/ctrl_exec.rb
|
64
|
+
- examples/run/ctrl_hanging.rb
|
66
65
|
- examples/run/myserver_crashing.rb.output
|
66
|
+
- examples/run/ctrl_proc_multiple.rb.output
|
67
67
|
- examples/run/myserver_exiting.rb
|
68
|
+
- examples/daemonize/daemonize.rb
|
68
69
|
has_rdoc: true
|
69
70
|
homepage: http://daemons.rubyforge.org
|
71
|
+
licenses: []
|
72
|
+
|
70
73
|
post_install_message:
|
71
74
|
rdoc_options: []
|
72
75
|
|
@@ -87,9 +90,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
90
|
requirements: []
|
88
91
|
|
89
92
|
rubyforge_project: daemons
|
90
|
-
rubygems_version: 1.
|
93
|
+
rubygems_version: 1.3.5
|
91
94
|
signing_key:
|
92
|
-
specification_version:
|
95
|
+
specification_version: 3
|
93
96
|
summary: A toolkit to create and control daemons in different ways
|
94
97
|
test_files: []
|
95
98
|
|