daemons 0.3.0 → 0.4.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/README +68 -2
- data/Rakefile +14 -1
- data/Releases +27 -11
- data/examples/call/call.rb +56 -0
- data/examples/call/call_monitor.rb +55 -0
- data/examples/daemonize/daemonize.rb +20 -0
- data/examples/{ctrl_crash.rb → run/ctrl_crash.rb} +1 -1
- data/examples/{ctrl_exec.rb → run/ctrl_exec.rb} +1 -1
- data/examples/{ctrl_exit.rb → run/ctrl_exit.rb} +1 -1
- data/examples/{ctrl_monitor.rb → run/ctrl_monitor.rb} +1 -1
- data/examples/{ctrl_multiple.rb → run/ctrl_multiple.rb} +1 -1
- data/examples/{ctrl_normal.rb → run/ctrl_normal.rb} +1 -1
- data/examples/{ctrl_ontop.rb → run/ctrl_ontop.rb} +1 -1
- data/examples/{myserver.rb → run/myserver.rb} +0 -0
- data/examples/{myserver_crashing.rb → run/myserver_crashing.rb} +0 -0
- data/examples/{myserver_crashing.rb.output → run/myserver_crashing.rb.output} +0 -0
- data/examples/{myserver_exiting.rb → run/myserver_exiting.rb} +0 -0
- data/lib/daemons.rb +151 -446
- data/lib/daemons/application.rb +289 -0
- data/lib/daemons/application_group.rb +152 -0
- data/lib/daemons/controller.rb +125 -0
- data/lib/daemons/daemonize.rb +98 -2
- data/lib/daemons/monitor.rb +58 -33
- data/lib/daemons/pid.rb +60 -0
- data/lib/daemons/pidfile.rb +7 -34
- data/lib/daemons/pidmem.rb +10 -0
- data/test/call_as_daemon.rb +12 -0
- metadata +40 -20
data/lib/daemons/daemonize.rb
CHANGED
@@ -112,6 +112,103 @@ module Daemonize
|
|
112
112
|
module_function :safefork
|
113
113
|
|
114
114
|
|
115
|
+
def simulate(logfile_name = nil)
|
116
|
+
# NOTE: STDOUT and STDERR will not be redirected to the logfile!
|
117
|
+
|
118
|
+
Dir.chdir "/" # Release old working directory
|
119
|
+
File.umask 0000 # Insure sensible umask
|
120
|
+
|
121
|
+
# Make sure all file descriptors are closed
|
122
|
+
ObjectSpace.each_object(IO) do |io|
|
123
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
124
|
+
begin
|
125
|
+
unless io.closed?
|
126
|
+
io.close
|
127
|
+
end
|
128
|
+
rescue ::Exception
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Free file descriptors and
|
134
|
+
# point them somewhere sensible
|
135
|
+
# STDOUT/STDERR should go to a logfile
|
136
|
+
|
137
|
+
STDIN.reopen "/dev/null" rescue nil
|
138
|
+
end
|
139
|
+
module_function :simulate
|
140
|
+
|
141
|
+
|
142
|
+
def call_as_daemon(block, logfile_name = nil, oldmode = 0)
|
143
|
+
rd, wr = IO.pipe
|
144
|
+
|
145
|
+
if tmppid = safefork
|
146
|
+
# parent
|
147
|
+
wr.close
|
148
|
+
pid = rd.read.to_i
|
149
|
+
rd.close
|
150
|
+
|
151
|
+
Process.waitpid(tmppid)
|
152
|
+
|
153
|
+
return pid
|
154
|
+
else
|
155
|
+
rd.close
|
156
|
+
|
157
|
+
# Detach from the controlling terminal
|
158
|
+
unless sess_id = Process.setsid
|
159
|
+
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
160
|
+
end
|
161
|
+
|
162
|
+
# Prevent the possibility of acquiring a controlling terminal
|
163
|
+
if oldmode.zero?
|
164
|
+
trap 'SIGHUP', 'IGNORE'
|
165
|
+
exit if pid = safefork
|
166
|
+
end
|
167
|
+
|
168
|
+
wr.write Process.pid
|
169
|
+
wr.close
|
170
|
+
|
171
|
+
Dir.chdir "/" # Release old working directory
|
172
|
+
File.umask 0000 # Insure sensible umask
|
173
|
+
|
174
|
+
# Make sure all file descriptors are closed
|
175
|
+
ObjectSpace.each_object(IO) do |io|
|
176
|
+
unless [STDIN, STDOUT, STDERR].include?(io)
|
177
|
+
begin
|
178
|
+
unless io.closed?
|
179
|
+
io.close
|
180
|
+
end
|
181
|
+
rescue ::Exception
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Free file descriptors and
|
187
|
+
# point them somewhere sensible
|
188
|
+
# STDOUT/STDERR should go to a logfile
|
189
|
+
|
190
|
+
STDIN.reopen "/dev/null" rescue nil
|
191
|
+
|
192
|
+
if logfile_name
|
193
|
+
begin
|
194
|
+
STDOUT.reopen logfile_name, "a"
|
195
|
+
rescue ::Exception
|
196
|
+
STDOUT.reopen "/dev/null" rescue nil
|
197
|
+
end
|
198
|
+
else
|
199
|
+
STDOUT.reopen "/dev/null" rescue nil
|
200
|
+
end
|
201
|
+
|
202
|
+
STDERR.reopen STDOUT rescue nil
|
203
|
+
|
204
|
+
block.call
|
205
|
+
|
206
|
+
exit
|
207
|
+
end
|
208
|
+
end
|
209
|
+
module_function :call_as_daemon
|
210
|
+
|
211
|
+
|
115
212
|
# This method causes the current running process to become a daemon
|
116
213
|
def daemonize(logfile_name = nil, oldmode=0)
|
117
214
|
srand # Split rand streams between spawning and daemonized process
|
@@ -119,7 +216,7 @@ module Daemonize
|
|
119
216
|
|
120
217
|
# Detach from the controlling terminal
|
121
218
|
unless sess_id = Process.setsid
|
122
|
-
raise Daemons.RuntimeException.new('cannot detach from
|
219
|
+
raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
|
123
220
|
end
|
124
221
|
|
125
222
|
# Prevent the possibility of acquiring a controlling terminal
|
@@ -161,7 +258,6 @@ module Daemonize
|
|
161
258
|
|
162
259
|
STDERR.reopen STDOUT rescue nil
|
163
260
|
|
164
|
-
|
165
261
|
return oldmode ? sess_id : 0 # Return value is mostly irrelevant
|
166
262
|
end
|
167
263
|
module_function :daemonize
|
data/lib/daemons/monitor.rb
CHANGED
@@ -6,19 +6,19 @@ module Daemons
|
|
6
6
|
class Monitor
|
7
7
|
|
8
8
|
def self.find(dir, app_name)
|
9
|
-
|
9
|
+
pid = PidFile.find_files(dir, app_name)[0]
|
10
10
|
|
11
|
-
if
|
12
|
-
|
11
|
+
if pid
|
12
|
+
pid = PidFile.existing(pid)
|
13
13
|
|
14
|
-
unless PidFile.running?(
|
15
|
-
|
14
|
+
unless PidFile.running?(pid.pid)
|
15
|
+
pid.cleanup rescue nil
|
16
16
|
return
|
17
17
|
end
|
18
18
|
|
19
19
|
monitor = self.allocate
|
20
20
|
|
21
|
-
monitor.instance_variable_set(:@
|
21
|
+
monitor.instance_variable_set(:@pid, pid)
|
22
22
|
|
23
23
|
return monitor
|
24
24
|
end
|
@@ -28,20 +28,44 @@ module Daemons
|
|
28
28
|
|
29
29
|
|
30
30
|
def initialize(an_app)
|
31
|
-
|
31
|
+
if an_app.pidfile_dir
|
32
|
+
@pid = PidFile.new(an_app.pidfile_dir, an_app.group.app_name + '_monitor', false)
|
33
|
+
else
|
34
|
+
@pid = PidMem.new
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
|
-
def
|
35
|
-
|
38
|
+
def watch(applications)
|
39
|
+
sleep(30)
|
36
40
|
|
41
|
+
loop do
|
42
|
+
applications.each {|a|
|
43
|
+
sleep(10)
|
44
|
+
|
45
|
+
unless a.running?
|
46
|
+
a.zap!
|
47
|
+
|
48
|
+
Process.detach(fork { a.start })
|
49
|
+
|
50
|
+
sleep(10)
|
51
|
+
end
|
52
|
+
}
|
53
|
+
|
54
|
+
sleep(30)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
private :watch
|
58
|
+
|
59
|
+
|
60
|
+
def start_with_pidfile(applications)
|
37
61
|
fork do
|
38
62
|
Daemonize.daemonize
|
39
63
|
|
40
64
|
begin
|
41
|
-
@
|
65
|
+
@pid.pid = Process.pid
|
42
66
|
|
43
67
|
# at_exit {
|
44
|
-
# @
|
68
|
+
# @pid.cleanup rescue nil
|
45
69
|
# }
|
46
70
|
|
47
71
|
# This part is needed to remove the pid-file if the application is killed by
|
@@ -50,50 +74,51 @@ module Daemons
|
|
50
74
|
# 'TERM'.
|
51
75
|
#
|
52
76
|
# trap('TERM') {
|
53
|
-
# @
|
77
|
+
# @pid.cleanup rescue nil
|
54
78
|
# exit
|
55
79
|
# }
|
56
80
|
|
57
|
-
|
58
|
-
|
59
|
-
loop do
|
60
|
-
applications.each {|a|
|
61
|
-
sleep(10)
|
62
|
-
|
63
|
-
unless a.running?
|
64
|
-
a.zap!
|
65
|
-
|
66
|
-
Process.detach(fork { a.start })
|
67
|
-
|
68
|
-
sleep(10)
|
69
|
-
end
|
70
|
-
}
|
71
|
-
|
72
|
-
sleep(30)
|
73
|
-
end
|
81
|
+
watch(applications)
|
74
82
|
rescue ::Exception => e
|
75
83
|
begin
|
76
|
-
File.open(File.join(@
|
84
|
+
File.open(File.join(@pid.dir, @pid.progname + '.log'), 'a') {|f|
|
77
85
|
f.puts Time.now
|
78
86
|
f.puts e
|
79
87
|
f.puts e.backtrace.inspect
|
80
88
|
}
|
81
89
|
ensure
|
82
|
-
@
|
90
|
+
@pid.cleanup rescue nil
|
83
91
|
exit!
|
84
92
|
end
|
85
93
|
end
|
86
94
|
end
|
95
|
+
end
|
96
|
+
private :start_with_pidfile
|
97
|
+
|
98
|
+
def start_without_pidfile(applications)
|
99
|
+
Thread.new { watch(applications) }
|
100
|
+
end
|
101
|
+
private :start_without_pidfile
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
def start(applications)
|
106
|
+
return if applications.empty?
|
87
107
|
|
108
|
+
if @pid.kind_of?(PidFile)
|
109
|
+
start_with_pidfile(applications)
|
110
|
+
else
|
111
|
+
start_without_pidfile(applications)
|
112
|
+
end
|
88
113
|
end
|
89
114
|
|
90
115
|
|
91
116
|
def stop
|
92
|
-
Process.kill('TERM', @
|
117
|
+
Process.kill('TERM', @pid.pid) rescue nil
|
93
118
|
|
94
119
|
# We try to remove the pid-files by ourselves, in case the application
|
95
120
|
# didn't clean it up.
|
96
|
-
@
|
121
|
+
@pid.cleanup rescue nil
|
97
122
|
end
|
98
123
|
|
99
124
|
end
|
data/lib/daemons/pid.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
|
4
|
+
class Pid
|
5
|
+
|
6
|
+
def Pid.running?(pid, additional = nil)
|
7
|
+
output = `ps ax`
|
8
|
+
return (/#{pid} / =~ output and (additional ? /#{additional}/ =~ output : true))
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
# Returns the directory that should be used to write the pid file to
|
13
|
+
# depending on the given mode.
|
14
|
+
#
|
15
|
+
# Some modes may require an additionaly hint, others may determine
|
16
|
+
# the directory automatically.
|
17
|
+
#
|
18
|
+
# If no valid directory is found, returns nil.
|
19
|
+
#
|
20
|
+
def Pid.dir(dir_mode, dir, script)
|
21
|
+
return nil unless script
|
22
|
+
|
23
|
+
case dir_mode
|
24
|
+
when :normal
|
25
|
+
return File.expand_path(dir_mode)
|
26
|
+
when :script
|
27
|
+
return File.expand_path(File.join(File.split(script)[0],dir))
|
28
|
+
when :system
|
29
|
+
return '/var/run'
|
30
|
+
else
|
31
|
+
raise Error.new("pid file mode '#{mode}' not implemented")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialization method
|
36
|
+
def initialize
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Get method
|
41
|
+
def pid
|
42
|
+
end
|
43
|
+
|
44
|
+
# Set method
|
45
|
+
def pid=(p)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Cleanup method
|
49
|
+
def cleanup
|
50
|
+
end
|
51
|
+
|
52
|
+
# Exists? method
|
53
|
+
def exists?
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
data/lib/daemons/pidfile.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'daemons/pid'
|
2
|
+
|
1
3
|
|
2
4
|
module Daemons
|
3
5
|
|
@@ -27,7 +29,7 @@ module Daemons
|
|
27
29
|
# 2. in a directory relative to the current directory or the filesystem root
|
28
30
|
# 3. in the preconfigured directory <tt>/var/run</tt>
|
29
31
|
#
|
30
|
-
class PidFile
|
32
|
+
class PidFile < Pid
|
31
33
|
|
32
34
|
attr_reader :dir, :progname, :multiple, :number
|
33
35
|
|
@@ -39,35 +41,6 @@ module Daemons
|
|
39
41
|
return files
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
def PidFile.running?(pid, additional = nil)
|
44
|
-
output = `ps ax`
|
45
|
-
return (/#{pid} / =~ output and (additional ? /#{additional}/ =~ output : true))
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
# Returns the directory that should be used to write the pid file to
|
50
|
-
# depending on the given mode.
|
51
|
-
#
|
52
|
-
# Some modes may require an additionaly hint, others may determine
|
53
|
-
# the directory automatically.
|
54
|
-
#
|
55
|
-
# If no valid directory is found, returns nil.
|
56
|
-
#
|
57
|
-
def PidFile.dir(dir_mode, dir, script)
|
58
|
-
case dir_mode
|
59
|
-
when :normal
|
60
|
-
return File.expand_path(dir_mode)
|
61
|
-
when :script
|
62
|
-
return File.expand_path(File.join(File.split(script)[0],dir))
|
63
|
-
when :system
|
64
|
-
return '/var/run'
|
65
|
-
else
|
66
|
-
raise Error.new("pid file mode '#{mode}' not implemented")
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
44
|
def PidFile.existing(path)
|
72
45
|
new_instance = PidFile.allocate
|
73
46
|
|
@@ -95,7 +68,7 @@ module Daemons
|
|
95
68
|
File.exists? filename
|
96
69
|
end
|
97
70
|
|
98
|
-
def
|
71
|
+
def pid=(p)
|
99
72
|
if multiple
|
100
73
|
while File.exists?(filename) and @number < 1024
|
101
74
|
@number += 1
|
@@ -107,15 +80,15 @@ module Daemons
|
|
107
80
|
end
|
108
81
|
|
109
82
|
File.open(filename, 'w') {|f|
|
110
|
-
f.puts Process.pid
|
83
|
+
f.puts p #Process.pid
|
111
84
|
}
|
112
85
|
end
|
113
86
|
|
114
|
-
def
|
87
|
+
def cleanup
|
115
88
|
File.delete(filename)
|
116
89
|
end
|
117
90
|
|
118
|
-
def
|
91
|
+
def pid
|
119
92
|
File.open(filename) {|f|
|
120
93
|
return f.gets.to_i
|
121
94
|
}
|
metadata
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: daemons
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-
|
8
|
-
summary: A toolkit to
|
6
|
+
version: 0.4.0
|
7
|
+
date: 2005-07-30 00:00:00 +02:00
|
8
|
+
summary: A toolkit to create and control daemons in different ways
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: th.uehlinger@gmx.ch
|
12
12
|
homepage: http://daemons.rubyforge.org
|
13
|
-
rubyforge_project:
|
14
|
-
description:
|
13
|
+
rubyforge_project: daemons
|
14
|
+
description: "Daemons provides an easy way to wrap existing ruby scripts (for example a
|
15
|
+
self-written server) to be run as a daemon and to be controlled by simple
|
16
|
+
start/stop/restart commands. You can also call blocks as daemons and control
|
17
|
+
them from the parent or just daemonize the current process. Besides this basic
|
18
|
+
functionality, daemons offers many advanced features like exception backtracing
|
19
|
+
and logging (in case your ruby script crashes) and monitoring and automatic
|
20
|
+
restarting of your processes if they crash."
|
15
21
|
autorequire: daemons
|
16
22
|
default_executable:
|
17
23
|
bindir: bin
|
@@ -24,6 +30,8 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
24
30
|
version: 0.0.0
|
25
31
|
version:
|
26
32
|
platform: ruby
|
33
|
+
signing_key:
|
34
|
+
cert_chain:
|
27
35
|
authors:
|
28
36
|
- Thomas Uehlinger
|
29
37
|
files:
|
@@ -33,26 +41,38 @@ files:
|
|
33
41
|
- README
|
34
42
|
- setup.rb
|
35
43
|
- lib/daemons.rb
|
36
|
-
- lib/daemons/daemonize.rb
|
37
|
-
- lib/daemons/exceptions.rb
|
38
44
|
- lib/daemons/cmdline.rb
|
45
|
+
- lib/daemons/exceptions.rb
|
46
|
+
- lib/daemons/daemonize.rb
|
39
47
|
- lib/daemons/pidfile.rb
|
40
48
|
- lib/daemons/monitor.rb
|
49
|
+
- lib/daemons/application_group.rb
|
50
|
+
- lib/daemons/controller.rb
|
51
|
+
- lib/daemons/pid.rb
|
52
|
+
- lib/daemons/pidmem.rb
|
53
|
+
- lib/daemons/application.rb
|
41
54
|
- test/tmp
|
42
55
|
- test/testapp.rb
|
43
|
-
- test/tc_main.rb
|
44
56
|
- test/test1.rb
|
45
|
-
-
|
46
|
-
-
|
47
|
-
- examples/
|
48
|
-
- examples/
|
49
|
-
- examples/
|
50
|
-
- examples/
|
51
|
-
- examples/
|
52
|
-
- examples/
|
53
|
-
- examples/
|
54
|
-
- examples/
|
55
|
-
- examples/ctrl_monitor.rb
|
57
|
+
- test/call_as_daemon.rb
|
58
|
+
- test/tc_main.rb
|
59
|
+
- examples/run
|
60
|
+
- examples/call
|
61
|
+
- examples/daemonize
|
62
|
+
- examples/run/ctrl_exec.rb
|
63
|
+
- examples/run/ctrl_exit.rb
|
64
|
+
- examples/run/ctrl_multiple.rb
|
65
|
+
- examples/run/myserver_crashing.rb.output
|
66
|
+
- examples/run/ctrl_normal.rb
|
67
|
+
- examples/run/ctrl_monitor.rb
|
68
|
+
- examples/run/myserver.rb
|
69
|
+
- examples/run/myserver_crashing.rb
|
70
|
+
- examples/run/ctrl_ontop.rb
|
71
|
+
- examples/run/myserver_exiting.rb
|
72
|
+
- examples/run/ctrl_crash.rb
|
73
|
+
- examples/call/call_monitor.rb
|
74
|
+
- examples/call/call.rb
|
75
|
+
- examples/daemonize/daemonize.rb
|
56
76
|
test_files:
|
57
77
|
- test/tc_main.rb
|
58
78
|
rdoc_options: []
|