daemons 0.2.1 → 0.3.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 +5 -1
- data/Releases +7 -1
- data/TODO +3 -0
- data/examples/ctrl_crash.rb +1 -0
- data/examples/ctrl_exit.rb +15 -0
- data/examples/ctrl_monitor.rb +16 -0
- data/examples/ctrl_multiple.rb +16 -0
- data/examples/myserver_crashing.rb.output +15 -0
- data/examples/myserver_exiting.rb +8 -0
- data/lib/daemons.rb +102 -29
- data/lib/daemons/cmdline.rb +4 -0
- data/lib/daemons/daemonize.rb +25 -6
- data/lib/daemons/monitor.rb +101 -0
- data/lib/daemons/pidfile.rb +6 -0
- metadata +9 -3
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Daemons Version 0.
|
1
|
+
= Daemons Version 0.3.0
|
2
2
|
|
3
3
|
(See Releases for release-specific information)
|
4
4
|
|
@@ -7,6 +7,10 @@
|
|
7
7
|
Daemons provides an easy way to wrap existing ruby scripts (for example a self-written server)
|
8
8
|
to be <i>run as a daemon</i> and to be <i>controlled by simple start/stop/restart commands</i>.
|
9
9
|
|
10
|
+
Besides this basic functionality, daemons offers many advanced features like <i>exception backtracing</i>
|
11
|
+
and logging (in case your ruby script crashes) and <i>monitoring</i> and automatic restarting of your processes
|
12
|
+
if they crash.
|
13
|
+
|
10
14
|
Daemons includes the <tt>daemonize.rb</tt> script written by <i>Travis Whitton</i> to do the daemonization
|
11
15
|
process.
|
12
16
|
|
data/Releases
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
* Initial release
|
6
6
|
|
7
|
-
|
8
7
|
== Release 0.2.0: Mar 21, 2005
|
9
8
|
|
10
9
|
* Exception backtrace functionality added
|
@@ -15,3 +14,10 @@
|
|
15
14
|
== Release 0.2.1: Mar 21, 2005
|
16
15
|
|
17
16
|
* Bugfix for a problem with the 'status' command
|
17
|
+
|
18
|
+
== Release 0.3.0: April 21, 2005
|
19
|
+
|
20
|
+
* New monitor functionality: automatic restarting of your applications if they crash
|
21
|
+
* 'restart' command fixed
|
22
|
+
* '--force' command modifier (please refer to the documentation)
|
23
|
+
* Some more bugfixes and improvements
|
data/TODO
CHANGED
data/examples/ctrl_crash.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
lib_dir = File.expand_path(File.join(File.split(__FILE__)[0], '../lib'))
|
2
|
+
|
3
|
+
if File.exists?(File.join(lib_dir, 'daemons.rb'))
|
4
|
+
$LOAD_PATH.unshift lib_dir
|
5
|
+
else
|
6
|
+
require 'rubygems' rescue nil
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'daemons'
|
10
|
+
|
11
|
+
|
12
|
+
options = {
|
13
|
+
}
|
14
|
+
|
15
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver_exiting.rb'), options)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
lib_dir = File.expand_path(File.join(File.split(__FILE__)[0], '../lib'))
|
2
|
+
|
3
|
+
if File.exists?(File.join(lib_dir, 'daemons.rb'))
|
4
|
+
$LOAD_PATH.unshift lib_dir
|
5
|
+
else
|
6
|
+
require 'rubygems' rescue nil
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'daemons'
|
10
|
+
|
11
|
+
|
12
|
+
options = {
|
13
|
+
:monitor => true
|
14
|
+
}
|
15
|
+
|
16
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver_crashing.rb'), options)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
lib_dir = File.expand_path(File.join(File.split(__FILE__)[0], '../lib'))
|
2
|
+
|
3
|
+
if File.exists?(File.join(lib_dir, 'daemons.rb'))
|
4
|
+
$LOAD_PATH.unshift lib_dir
|
5
|
+
else
|
6
|
+
require 'rubygems' rescue nil
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'daemons'
|
10
|
+
|
11
|
+
|
12
|
+
options = {
|
13
|
+
:multiple => true
|
14
|
+
}
|
15
|
+
|
16
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver.rb'), options)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:13: CRASH! (RuntimeError)
|
2
|
+
from /home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:6:in `loop'
|
3
|
+
from /home/uehli/Desktop/daemons-current/examples/myserver_crashing.rb:6
|
4
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:116:in `load'
|
5
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:116:in `run_via_load'
|
6
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:90:in `start'
|
7
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:359:in `run'
|
8
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:469:in `run'
|
9
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:468:in `call'
|
10
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons/cmdline.rb:94:in `catch_exceptions'
|
11
|
+
from /home/uehli/Desktop/daemons-current/lib/daemons.rb:468:in `run'
|
12
|
+
from ctrl_crash.rb:17
|
13
|
+
ping from myserver.rb!
|
14
|
+
this example server will crash in 3 seconds...
|
15
|
+
CRASH!
|
data/lib/daemons.rb
CHANGED
@@ -4,6 +4,7 @@ require 'optparse/time'
|
|
4
4
|
require 'daemons/pidfile'
|
5
5
|
require 'daemons/cmdline'
|
6
6
|
require 'daemons/exceptions'
|
7
|
+
require 'daemons/monitor'
|
7
8
|
|
8
9
|
|
9
10
|
# All functions and classes that Daemons provides reside in this module.
|
@@ -17,7 +18,7 @@ require 'daemons/exceptions'
|
|
17
18
|
#
|
18
19
|
module Daemons
|
19
20
|
|
20
|
-
VERSION = "0.
|
21
|
+
VERSION = "0.3.0"
|
21
22
|
|
22
23
|
require 'daemons/daemonize'
|
23
24
|
|
@@ -48,11 +49,11 @@ module Daemons
|
|
48
49
|
PidFile.dir(@dir_mode || @group.dir_mode, @dir || @group.dir, @script || @group.script)
|
49
50
|
end
|
50
51
|
|
51
|
-
def
|
52
|
+
def real_start
|
52
53
|
opts = @group.controller.options
|
53
54
|
|
54
55
|
unless opts[:ontop]
|
55
|
-
Daemonize.daemonize()
|
56
|
+
Daemonize.daemonize(opts[:log_output] ? File.join(pidfile_dir(), @group.app_name + '.output') : nil)
|
56
57
|
end
|
57
58
|
|
58
59
|
@pid_file.write
|
@@ -90,6 +91,13 @@ module Daemons
|
|
90
91
|
run_via_load()
|
91
92
|
end
|
92
93
|
end
|
94
|
+
private :real_start
|
95
|
+
|
96
|
+
def start
|
97
|
+
@group.create_monitor(@group.applications[0] || self)
|
98
|
+
|
99
|
+
real_start
|
100
|
+
end
|
93
101
|
|
94
102
|
def run
|
95
103
|
if @group.controller.options[:exec]
|
@@ -132,31 +140,34 @@ module Daemons
|
|
132
140
|
|
133
141
|
|
134
142
|
# the code below only logs the last exception
|
135
|
-
|
143
|
+
# e = nil
|
144
|
+
#
|
145
|
+
# ObjectSpace.each_object {|o|
|
146
|
+
# if ::Exception === o
|
147
|
+
# e = o
|
148
|
+
# end
|
149
|
+
# }
|
150
|
+
#
|
151
|
+
# l_file.error e
|
152
|
+
# l_file.close
|
136
153
|
|
154
|
+
# this code logs every exception found in memory
|
137
155
|
ObjectSpace.each_object {|o|
|
138
156
|
if ::Exception === o
|
139
|
-
|
157
|
+
l_file.error o
|
140
158
|
end
|
141
159
|
}
|
142
160
|
|
143
|
-
l_file.error e
|
144
161
|
l_file.close
|
145
|
-
|
146
|
-
e = nil
|
147
|
-
|
148
|
-
# this code logs every exception found in memory
|
149
|
-
# ObjectSpace.each_object {|o|
|
150
|
-
# if ::Exception === o
|
151
|
-
# l_file.error o
|
152
|
-
# end
|
153
|
-
# }
|
154
|
-
#
|
155
|
-
# l_file.close
|
156
162
|
end
|
157
163
|
|
158
164
|
|
159
165
|
def stop
|
166
|
+
if @group.controller.options[:force] and not running?
|
167
|
+
self.zap
|
168
|
+
return
|
169
|
+
end
|
170
|
+
|
160
171
|
Process.kill('TERM', @pid_file.read)
|
161
172
|
|
162
173
|
# We try to remove the pid-files by ourselves, in case the application
|
@@ -169,10 +180,14 @@ module Daemons
|
|
169
180
|
@pid_file.remove
|
170
181
|
end
|
171
182
|
|
183
|
+
def zap!
|
184
|
+
@pid_file.remove rescue nil
|
185
|
+
end
|
186
|
+
|
172
187
|
def show_status
|
173
188
|
running = self.running?
|
174
189
|
|
175
|
-
puts "#{self.group.app_name}: #{running ? '' : 'not'}
|
190
|
+
puts "#{self.group.app_name}: #{running ? '' : 'not '}running#{(running and @pid_file.exists?) ? ' [pid ' + @pid_file.read.to_s + ']' : ''}#{(@pid_file.exists? and not running) ? ' (but pid-file exists: ' + @pid_file.read.to_s + ')' : ''}"
|
176
191
|
end
|
177
192
|
|
178
193
|
# This function implements a (probably too simle) method to detect
|
@@ -184,7 +199,7 @@ module Daemons
|
|
184
199
|
#
|
185
200
|
def running?
|
186
201
|
if @pid_file.exists?
|
187
|
-
return
|
202
|
+
return PidFile.running?(@pid_file.read)
|
188
203
|
end
|
189
204
|
|
190
205
|
return false
|
@@ -197,6 +212,7 @@ module Daemons
|
|
197
212
|
attr_reader :app_name
|
198
213
|
attr_reader :script
|
199
214
|
|
215
|
+
attr_reader :monitor
|
200
216
|
attr_reader :controller
|
201
217
|
|
202
218
|
attr_reader :applications
|
@@ -215,6 +231,7 @@ module Daemons
|
|
215
231
|
@app_name = app_name
|
216
232
|
@script = script
|
217
233
|
@controller = controller
|
234
|
+
@monitor = nil
|
218
235
|
|
219
236
|
options = controller.options
|
220
237
|
|
@@ -223,6 +240,14 @@ module Daemons
|
|
223
240
|
@dir_mode = options[:dir_mode] || :script
|
224
241
|
@dir = options[:dir] || ''
|
225
242
|
|
243
|
+
#@applications = find_applications(pidfile_dir())
|
244
|
+
end
|
245
|
+
|
246
|
+
# Setup the application group.
|
247
|
+
# Currently this functions calls <tt>find_applications</tt> which finds
|
248
|
+
# all running instances of the application and populates the application array.
|
249
|
+
#
|
250
|
+
def setup
|
226
251
|
@applications = find_applications(pidfile_dir())
|
227
252
|
end
|
228
253
|
|
@@ -235,33 +260,76 @@ module Daemons
|
|
235
260
|
|
236
261
|
#pp pid_files
|
237
262
|
|
238
|
-
|
263
|
+
@monitor = Monitor.find(dir, app_name + '_monitor')
|
264
|
+
|
265
|
+
pid_files.reject! {|f| f =~ /_monitor.pid$/}
|
266
|
+
|
267
|
+
return pid_files.map {|f|
|
268
|
+
app = Application.new(self, PidFile.existing(f))
|
269
|
+
setup_app(app)
|
270
|
+
app
|
271
|
+
}
|
239
272
|
end
|
240
273
|
|
241
274
|
def new_application(script = nil)
|
242
275
|
if @applications.size > 0 and not @multiple
|
243
|
-
|
276
|
+
if @controller.options[:force]
|
277
|
+
@applications.delete_if {|a|
|
278
|
+
unless a.running?
|
279
|
+
a.zap
|
280
|
+
true
|
281
|
+
end
|
282
|
+
}
|
283
|
+
end
|
284
|
+
|
285
|
+
raise RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
|
244
286
|
end
|
245
287
|
|
246
288
|
app = Application.new(self)
|
247
289
|
|
248
|
-
app
|
249
|
-
app.app_argv = @app_argv
|
290
|
+
setup_app(app)
|
250
291
|
|
251
292
|
@applications << app
|
252
293
|
|
253
294
|
return app
|
254
295
|
end
|
255
296
|
|
297
|
+
def setup_app(app)
|
298
|
+
app.controller_argv = @controller_argv
|
299
|
+
app.app_argv = @app_argv
|
300
|
+
end
|
301
|
+
private :setup_app
|
302
|
+
|
303
|
+
def create_monitor(an_app)
|
304
|
+
return if @monitor
|
305
|
+
|
306
|
+
if @controller.options[:monitor]
|
307
|
+
@monitor = Monitor.new(an_app)
|
308
|
+
|
309
|
+
@monitor.start(@applications)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
256
313
|
def start_all
|
257
|
-
@
|
314
|
+
@monitor.stop if @monitor
|
315
|
+
@monitor = nil
|
316
|
+
|
317
|
+
@applications.each {|a|
|
318
|
+
fork {
|
319
|
+
a.start
|
320
|
+
}
|
321
|
+
}
|
258
322
|
end
|
259
323
|
|
260
324
|
def stop_all
|
325
|
+
@monitor.stop if @monitor
|
326
|
+
|
261
327
|
@applications.each {|a| a.stop}
|
262
328
|
end
|
263
329
|
|
264
330
|
def zap_all
|
331
|
+
@monitor.stop if @monitor
|
332
|
+
|
265
333
|
@applications.each {|a| a.zap}
|
266
334
|
end
|
267
335
|
|
@@ -323,6 +391,8 @@ module Daemons
|
|
323
391
|
@group.controller_argv = @controller_part
|
324
392
|
@group.app_argv = @app_part
|
325
393
|
|
394
|
+
@group.setup
|
395
|
+
|
326
396
|
case @command
|
327
397
|
when 'start'
|
328
398
|
@group.new_application.start
|
@@ -331,9 +401,11 @@ module Daemons
|
|
331
401
|
when 'stop'
|
332
402
|
@group.stop_all
|
333
403
|
when 'restart'
|
334
|
-
@group.
|
335
|
-
|
336
|
-
|
404
|
+
unless @group.applications.empty?
|
405
|
+
@group.stop_all
|
406
|
+
sleep 1
|
407
|
+
@group.start_all
|
408
|
+
end
|
337
409
|
when 'zap'
|
338
410
|
@group.zap_all
|
339
411
|
when 'status'
|
@@ -412,7 +484,7 @@ module Daemons
|
|
412
484
|
# but by exec'ing the script file
|
413
485
|
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
|
414
486
|
# pid-file directory if the application exits due to an uncaught exception
|
415
|
-
#
|
487
|
+
# <tt>:monitor</tt>:: Monitor the programs and restart crashed instances
|
416
488
|
# -----
|
417
489
|
#
|
418
490
|
# === Example:
|
@@ -422,7 +494,8 @@ module Daemons
|
|
422
494
|
# :multiple => true,
|
423
495
|
# :ontop => true,
|
424
496
|
# :exec => true,
|
425
|
-
# :backtrace => true
|
497
|
+
# :backtrace => true,
|
498
|
+
# :monitor => true
|
426
499
|
# }
|
427
500
|
#
|
428
501
|
# Daemons.run(File.join(File.split(__FILE__)[0], 'myscript.rb'), options)
|
data/lib/daemons/cmdline.rb
CHANGED
data/lib/daemons/daemonize.rb
CHANGED
@@ -113,7 +113,7 @@ module Daemonize
|
|
113
113
|
|
114
114
|
|
115
115
|
# This method causes the current running process to become a daemon
|
116
|
-
def daemonize(oldmode=0)
|
116
|
+
def daemonize(logfile_name = nil, oldmode=0)
|
117
117
|
srand # Split rand streams between spawning and daemonized process
|
118
118
|
safefork and exit # Fork and exit from the parent
|
119
119
|
|
@@ -134,15 +134,34 @@ module Daemonize
|
|
134
134
|
# Make sure all file descriptors are closed
|
135
135
|
ObjectSpace.each_object(IO) do |io|
|
136
136
|
unless [STDIN, STDOUT, STDERR].include?(io)
|
137
|
-
|
138
|
-
io.
|
137
|
+
begin
|
138
|
+
unless io.closed?
|
139
|
+
io.close
|
140
|
+
end
|
141
|
+
rescue ::Exception
|
139
142
|
end
|
140
143
|
end
|
141
144
|
end
|
142
145
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
+
# Free file descriptors and
|
147
|
+
# point them somewhere sensible
|
148
|
+
# STDOUT/STDERR should go to a logfile
|
149
|
+
|
150
|
+
STDIN.reopen "/dev/null" rescue nil
|
151
|
+
|
152
|
+
if logfile_name
|
153
|
+
begin
|
154
|
+
STDOUT.reopen logfile_name, "a"
|
155
|
+
rescue ::Exception
|
156
|
+
STDOUT.reopen "/dev/null" rescue nil
|
157
|
+
end
|
158
|
+
else
|
159
|
+
STDOUT.reopen "/dev/null" rescue nil
|
160
|
+
end
|
161
|
+
|
162
|
+
STDERR.reopen STDOUT rescue nil
|
163
|
+
|
164
|
+
|
146
165
|
return oldmode ? sess_id : 0 # Return value is mostly irrelevant
|
147
166
|
end
|
148
167
|
module_function :daemonize
|
@@ -0,0 +1,101 @@
|
|
1
|
+
|
2
|
+
module Daemons
|
3
|
+
|
4
|
+
require 'daemons/daemonize'
|
5
|
+
|
6
|
+
class Monitor
|
7
|
+
|
8
|
+
def self.find(dir, app_name)
|
9
|
+
pid_file = PidFile.find_files(dir, app_name)[0]
|
10
|
+
|
11
|
+
if pid_file
|
12
|
+
pid_file = PidFile.existing(pid_file)
|
13
|
+
|
14
|
+
unless PidFile.running?(pid_file.read)
|
15
|
+
pid_file.remove rescue nil
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
monitor = self.allocate
|
20
|
+
|
21
|
+
monitor.instance_variable_set(:@pid_file, pid_file)
|
22
|
+
|
23
|
+
return monitor
|
24
|
+
end
|
25
|
+
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def initialize(an_app)
|
31
|
+
@pid_file = PidFile.new(an_app.pidfile_dir, an_app.group.app_name + '_monitor', false)
|
32
|
+
end
|
33
|
+
|
34
|
+
def start(applications)
|
35
|
+
return if applications.empty?
|
36
|
+
|
37
|
+
fork do
|
38
|
+
Daemonize.daemonize
|
39
|
+
|
40
|
+
begin
|
41
|
+
@pid_file.write
|
42
|
+
|
43
|
+
# at_exit {
|
44
|
+
# @pid_file.remove rescue nil
|
45
|
+
# }
|
46
|
+
|
47
|
+
# This part is needed to remove the pid-file if the application is killed by
|
48
|
+
# daemons or manually by the user.
|
49
|
+
# Note that the applications is not supposed to overwrite the signal handler for
|
50
|
+
# 'TERM'.
|
51
|
+
#
|
52
|
+
# trap('TERM') {
|
53
|
+
# @pid_file.remove rescue nil
|
54
|
+
# exit
|
55
|
+
# }
|
56
|
+
|
57
|
+
sleep(60)
|
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
|
74
|
+
rescue ::Exception => e
|
75
|
+
begin
|
76
|
+
File.open(File.join(@pid_file.dir, @pid_file.progname + '.log'), 'a') {|f|
|
77
|
+
f.puts Time.now
|
78
|
+
f.puts e
|
79
|
+
f.puts e.backtrace.inspect
|
80
|
+
}
|
81
|
+
ensure
|
82
|
+
@pid_file.remove rescue nil
|
83
|
+
exit!
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def stop
|
92
|
+
Process.kill('TERM', @pid_file.read) rescue nil
|
93
|
+
|
94
|
+
# We try to remove the pid-files by ourselves, in case the application
|
95
|
+
# didn't clean it up.
|
96
|
+
@pid_file.remove rescue nil
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
data/lib/daemons/pidfile.rb
CHANGED
@@ -40,6 +40,12 @@ module Daemons
|
|
40
40
|
end
|
41
41
|
|
42
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
|
+
|
43
49
|
# Returns the directory that should be used to write the pid file to
|
44
50
|
# depending on the given mode.
|
45
51
|
#
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.8
|
|
3
3
|
specification_version: 1
|
4
4
|
name: daemons
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2005-
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2005-04-21
|
8
8
|
summary: A toolkit to convert your script to a controllable daemon
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -37,16 +37,22 @@ files:
|
|
37
37
|
- lib/daemons/exceptions.rb
|
38
38
|
- lib/daemons/cmdline.rb
|
39
39
|
- lib/daemons/pidfile.rb
|
40
|
+
- lib/daemons/monitor.rb
|
41
|
+
- test/tmp
|
40
42
|
- test/testapp.rb
|
41
43
|
- test/tc_main.rb
|
42
44
|
- test/test1.rb
|
43
|
-
- test/tmp
|
44
45
|
- examples/myserver.rb
|
45
46
|
- examples/myserver_crashing.rb
|
46
47
|
- examples/ctrl_crash.rb
|
47
48
|
- examples/ctrl_ontop.rb
|
48
49
|
- examples/ctrl_exec.rb
|
49
50
|
- examples/ctrl_normal.rb
|
51
|
+
- examples/ctrl_multiple.rb
|
52
|
+
- examples/myserver_exiting.rb
|
53
|
+
- examples/ctrl_exit.rb
|
54
|
+
- examples/myserver_crashing.rb.output
|
55
|
+
- examples/ctrl_monitor.rb
|
50
56
|
test_files:
|
51
57
|
- test/tc_main.rb
|
52
58
|
rdoc_options: []
|