daemons 0.0.1 → 0.2.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 +1 -1
- data/Rakefile +5 -4
- data/Releases +8 -1
- data/TODO +2 -1
- data/examples/ctrl_crash.rb +16 -0
- data/examples/ctrl_exec.rb +16 -0
- data/examples/ctrl_normal.rb +12 -0
- data/examples/ctrl_ontop.rb +16 -0
- data/examples/myserver.rb +12 -0
- data/examples/myserver_crashing.rb +14 -0
- data/lib/daemons.rb +162 -29
- data/lib/daemons/cmdline.rb +1 -0
- data/lib/daemons/daemonize.rb +7 -3
- metadata +9 -3
data/README
CHANGED
data/Rakefile
CHANGED
|
@@ -16,14 +16,15 @@ PKG_FILES = FileList[
|
|
|
16
16
|
"Rakefile", "Releases", "TODO", "README",
|
|
17
17
|
"setup.rb",
|
|
18
18
|
"lib/**/*.rb",
|
|
19
|
-
"test/**/*"
|
|
19
|
+
"test/**/*",
|
|
20
|
+
"examples/**/*"
|
|
20
21
|
]
|
|
21
|
-
PKG_FILES.exclude(%r(^test/tmp/.+))
|
|
22
|
-
|
|
22
|
+
#PKG_FILES.exclude(%r(^test/tmp/.+))
|
|
23
|
+
PKG_FILES.exclude(%r(\.pid$))
|
|
24
|
+
PKG_FILES.exclude(%r(\.log$))
|
|
23
25
|
|
|
24
26
|
spec = Gem::Specification.new do |s|
|
|
25
27
|
s.name = PKG_NAME
|
|
26
|
-
#s.version = "0.0.1"
|
|
27
28
|
s.version = Daemons::VERSION
|
|
28
29
|
s.author = "Thomas Uehlinger"
|
|
29
30
|
s.email = "th.uehlinger@gmx.ch"
|
data/Releases
CHANGED
data/TODO
CHANGED
|
@@ -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
|
+
:backtrace => 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
|
+
:exec => true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver.rb'), options)
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver.rb'))
|
|
@@ -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
|
+
:ontop => true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Daemons.run(File.join(File.split(__FILE__)[0], 'myserver.rb'), options)
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
loop do
|
|
10
|
+
puts 'ping from myserver.rb!'
|
|
11
|
+
sleep(3)
|
|
12
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# This is myserver.rb, an example server that is to be controlled by daemons
|
|
2
|
+
# and that does nothing really useful at the moment.
|
|
3
|
+
#
|
|
4
|
+
# Don't run this script by yourself, it can be controlled by the ctrl*.rb scripts.
|
|
5
|
+
|
|
6
|
+
loop do
|
|
7
|
+
puts 'ping from myserver.rb!'
|
|
8
|
+
puts 'this example server will crash in 3 seconds...'
|
|
9
|
+
|
|
10
|
+
sleep(3)
|
|
11
|
+
|
|
12
|
+
puts 'CRASH!'
|
|
13
|
+
raise 'CRASH!'
|
|
14
|
+
end
|
data/lib/daemons.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require 'optparse'
|
|
2
2
|
require 'optparse/time'
|
|
3
|
-
#require 'ostruct'
|
|
4
3
|
|
|
5
4
|
require 'daemons/pidfile'
|
|
6
5
|
require 'daemons/cmdline'
|
|
@@ -18,7 +17,7 @@ require 'daemons/exceptions'
|
|
|
18
17
|
#
|
|
19
18
|
module Daemons
|
|
20
19
|
|
|
21
|
-
VERSION = "0.0
|
|
20
|
+
VERSION = "0.2.0"
|
|
22
21
|
|
|
23
22
|
require 'daemons/daemonize'
|
|
24
23
|
|
|
@@ -28,8 +27,12 @@ module Daemons
|
|
|
28
27
|
attr_accessor :app_argv
|
|
29
28
|
attr_accessor :controller_argv
|
|
30
29
|
|
|
30
|
+
# the PidFile instance belonging to this application
|
|
31
31
|
attr_reader :pid_file
|
|
32
32
|
|
|
33
|
+
# the ApplicationGroup the application belongs to
|
|
34
|
+
attr_reader :group
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
def initialize(group, pid_file = nil)
|
|
35
38
|
@group = group
|
|
@@ -46,42 +49,145 @@ module Daemons
|
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
def start
|
|
49
|
-
|
|
52
|
+
opts = @group.controller.options
|
|
50
53
|
|
|
51
|
-
unless
|
|
54
|
+
unless opts[:ontop]
|
|
52
55
|
Daemonize.daemonize()
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
@pid_file.write
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
if opts[:exec]
|
|
61
|
+
run_via_exec()
|
|
62
|
+
else
|
|
63
|
+
# We need this to remove the pid-file if the applications exits by itself.
|
|
64
|
+
# Note that <tt>at_text</tt> will only be run if the applications exits by calling
|
|
65
|
+
# <tt>exit</tt>, and not if it calls <tt>exit!</tt>.
|
|
66
|
+
#
|
|
67
|
+
at_exit {
|
|
68
|
+
@pid_file.remove rescue nil
|
|
69
|
+
|
|
70
|
+
# If the option <tt>:backtrace</tt> is used and the application did exit by itself
|
|
71
|
+
# create a exception log.
|
|
72
|
+
if opts[:backtrace] and not opts[:ontop] and not $daemons_sigterm
|
|
73
|
+
exception_log() rescue nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# This part is needed to remove the pid-file if the application is killed by
|
|
79
|
+
# daemons or manually by the user.
|
|
80
|
+
# Note that the applications is not supposed to overwrite the signal handler for
|
|
81
|
+
# 'TERM'.
|
|
82
|
+
#
|
|
83
|
+
trap('TERM') {
|
|
84
|
+
@pid_file.remove rescue nil
|
|
85
|
+
$daemons_sigterm = true
|
|
86
|
+
|
|
87
|
+
exit
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
run_via_load()
|
|
91
|
+
end
|
|
67
92
|
end
|
|
68
93
|
|
|
69
94
|
def run
|
|
95
|
+
if @group.controller.options[:exec]
|
|
96
|
+
run_via_exec()
|
|
97
|
+
else
|
|
98
|
+
run_via_load()
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def run_via_exec
|
|
103
|
+
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ') # haven't tested yet if this is really passed to the exec'd process...
|
|
104
|
+
|
|
105
|
+
Kernel.exec(script(), *ARGV)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def run_via_load
|
|
70
109
|
$DAEMONS_ARGV = @controller_argv
|
|
110
|
+
ENV['DAEMONS_ARGV'] = @controller_argv.join(' ')
|
|
71
111
|
|
|
72
112
|
ARGV.clear
|
|
73
113
|
ARGV.concat @app_argv if @app_argv
|
|
74
114
|
|
|
115
|
+
# TODO: begin - rescue - end around this and exception logging
|
|
75
116
|
load script()
|
|
76
117
|
end
|
|
77
118
|
|
|
119
|
+
# This is a nice little function for debugging purposes:
|
|
120
|
+
# In case a multi-threaded ruby script exits due to an uncaught exception
|
|
121
|
+
# it may be difficult to find out where the exception came from because
|
|
122
|
+
# one cannot catch exceptions that are thrown in threads other than the main
|
|
123
|
+
# thread.
|
|
124
|
+
#
|
|
125
|
+
# This function searches for all exceptions in memory and outputs them to STDERR
|
|
126
|
+
# (if it is connected) and to a log file in the pid-file directory.
|
|
127
|
+
#
|
|
128
|
+
def exception_log
|
|
129
|
+
require 'logger'
|
|
130
|
+
|
|
131
|
+
l_file = Logger.new(File.join(pidfile_dir(), @group.app_name + '.log'))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# the code below only logs the last exception
|
|
135
|
+
e = nil
|
|
136
|
+
|
|
137
|
+
ObjectSpace.each_object {|o|
|
|
138
|
+
if ::Exception === o
|
|
139
|
+
e = o
|
|
140
|
+
end
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
l_file.error e
|
|
144
|
+
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
|
+
end
|
|
157
|
+
|
|
158
|
+
|
|
78
159
|
def stop
|
|
79
160
|
Process.kill('TERM', @pid_file.read)
|
|
80
161
|
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
|
|
84
|
-
|
|
162
|
+
# We try to remove the pid-files by ourselves, in case the application
|
|
163
|
+
# didn't clean it up.
|
|
164
|
+
@pid_file.remove rescue nil
|
|
165
|
+
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def zap
|
|
169
|
+
@pid_file.remove
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def show_status
|
|
173
|
+
running = self.running?
|
|
174
|
+
|
|
175
|
+
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
|
+
end
|
|
177
|
+
|
|
178
|
+
# This function implements a (probably too simle) method to detect
|
|
179
|
+
# whether the program with the pid found in the pid-file is still running.
|
|
180
|
+
# It just searches for the pid in the output of <tt>ps ax</tt>, which
|
|
181
|
+
# is probably not a good idea in some cases.
|
|
182
|
+
# Alternatives would be to use a direct access method the unix process control
|
|
183
|
+
# system.
|
|
184
|
+
#
|
|
185
|
+
def running?
|
|
186
|
+
if @pid_file.exists?
|
|
187
|
+
return / #{@pid_file.read} / =~ `ps ax`
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
return false
|
|
85
191
|
end
|
|
86
192
|
end
|
|
87
193
|
|
|
@@ -93,11 +199,6 @@ module Daemons
|
|
|
93
199
|
|
|
94
200
|
attr_reader :controller
|
|
95
201
|
|
|
96
|
-
# True if one can start multiple instances of the application
|
|
97
|
-
#attr_reader :multiple
|
|
98
|
-
|
|
99
|
-
#attr_reader :options
|
|
100
|
-
|
|
101
202
|
attr_reader :applications
|
|
102
203
|
|
|
103
204
|
attr_accessor :controller_argv
|
|
@@ -106,8 +207,10 @@ module Daemons
|
|
|
106
207
|
attr_accessor :dir_mode
|
|
107
208
|
attr_accessor :dir
|
|
108
209
|
|
|
210
|
+
# true if the application is supposed to run in multiple instances
|
|
109
211
|
attr_reader :multiple
|
|
110
212
|
|
|
213
|
+
|
|
111
214
|
def initialize(app_name, script, controller) #multiple = false)
|
|
112
215
|
@app_name = app_name
|
|
113
216
|
@script = script
|
|
@@ -120,8 +223,6 @@ module Daemons
|
|
|
120
223
|
@dir_mode = options[:dir_mode] || :script
|
|
121
224
|
@dir = options[:dir] || ''
|
|
122
225
|
|
|
123
|
-
#@multiple = multiple
|
|
124
|
-
|
|
125
226
|
@applications = find_applications(pidfile_dir())
|
|
126
227
|
end
|
|
127
228
|
|
|
@@ -159,10 +260,18 @@ module Daemons
|
|
|
159
260
|
def stop_all
|
|
160
261
|
@applications.each {|a| a.stop}
|
|
161
262
|
end
|
|
263
|
+
|
|
264
|
+
def zap_all
|
|
265
|
+
@applications.each {|a| a.zap}
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def show_status
|
|
269
|
+
@applications.each {|a| a.show_status}
|
|
270
|
+
end
|
|
271
|
+
|
|
162
272
|
end
|
|
163
273
|
|
|
164
274
|
|
|
165
|
-
|
|
166
275
|
class Controller
|
|
167
276
|
|
|
168
277
|
attr_reader :app_name
|
|
@@ -173,7 +282,9 @@ module Daemons
|
|
|
173
282
|
'start',
|
|
174
283
|
'stop',
|
|
175
284
|
'restart',
|
|
176
|
-
'run'
|
|
285
|
+
'run',
|
|
286
|
+
'zap',
|
|
287
|
+
'status'
|
|
177
288
|
]
|
|
178
289
|
|
|
179
290
|
def initialize(script, argv = [])
|
|
@@ -190,6 +301,11 @@ module Daemons
|
|
|
190
301
|
end
|
|
191
302
|
|
|
192
303
|
|
|
304
|
+
# This function is used to do a final update of the options passed to the application
|
|
305
|
+
# before they are really used.
|
|
306
|
+
#
|
|
307
|
+
# Note that this function should only update <tt>@options</tt> and no other variables.
|
|
308
|
+
#
|
|
193
309
|
def setup_options
|
|
194
310
|
#@options[:ontop] ||= true
|
|
195
311
|
end
|
|
@@ -218,6 +334,14 @@ module Daemons
|
|
|
218
334
|
@group.stop_all
|
|
219
335
|
sleep 1
|
|
220
336
|
@group.start_all
|
|
337
|
+
when 'zap'
|
|
338
|
+
@group.zap_all
|
|
339
|
+
when 'status'
|
|
340
|
+
unless @group.applications.empty?
|
|
341
|
+
@group.show_status
|
|
342
|
+
else
|
|
343
|
+
puts "#{@group.app_name}: no instances running"
|
|
344
|
+
end
|
|
221
345
|
when nil
|
|
222
346
|
raise CmdException.new('no command given')
|
|
223
347
|
#puts "ERROR: No command given"; puts
|
|
@@ -225,7 +349,7 @@ module Daemons
|
|
|
225
349
|
#print_usage()
|
|
226
350
|
#raise('usage function not implemented')
|
|
227
351
|
else
|
|
228
|
-
raise Error.new("
|
|
352
|
+
raise Error.new("command '#{@command}' not implemented")
|
|
229
353
|
end
|
|
230
354
|
end
|
|
231
355
|
|
|
@@ -282,6 +406,12 @@ module Daemons
|
|
|
282
406
|
# <tt>:dir</tt>:: Used in combination with <tt>:dir_mode</tt> (description above)
|
|
283
407
|
# <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
|
|
284
408
|
# same time
|
|
409
|
+
# <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
|
|
410
|
+
# (but the pid-file and other things are written as usual)
|
|
411
|
+
# <tt>:exec</tt>:: When given, do not start the application by <tt>load</tt>-ing the script file,
|
|
412
|
+
# but by exec'ing the script file
|
|
413
|
+
# <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
|
|
414
|
+
# pid-file directory if the application exits due to an uncaught exception
|
|
285
415
|
#
|
|
286
416
|
# -----
|
|
287
417
|
#
|
|
@@ -289,7 +419,10 @@ module Daemons
|
|
|
289
419
|
# options = {
|
|
290
420
|
# :dir_mode => :script,
|
|
291
421
|
# :dir => 'pids',
|
|
292
|
-
# :multiple => true
|
|
422
|
+
# :multiple => true,
|
|
423
|
+
# :ontop => true,
|
|
424
|
+
# :exec => true,
|
|
425
|
+
# :backtrace => true
|
|
293
426
|
# }
|
|
294
427
|
#
|
|
295
428
|
# Daemons.run(File.join(File.split(__FILE__)[0], 'myscript.rb'), options)
|
data/lib/daemons/cmdline.rb
CHANGED
|
@@ -78,6 +78,7 @@ module Daemons
|
|
|
78
78
|
puts " stop stop all instances of the application"
|
|
79
79
|
puts " restart stop all instances and restart them afterwards"
|
|
80
80
|
puts " run start the application and stay on top"
|
|
81
|
+
puts " zap set the application to a stopped state"
|
|
81
82
|
puts
|
|
82
83
|
puts "* and where <options> may contain several of the following:"
|
|
83
84
|
|
data/lib/daemons/daemonize.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
#--
|
|
1
2
|
###############################################################################
|
|
2
3
|
# daemonize.rb is a slightly modified version of daemonize.rb was #
|
|
3
4
|
# from the Daemonize Library written by Travis Whitton #
|
|
4
5
|
# for details, read the notice below #
|
|
5
6
|
###############################################################################
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
#++
|
|
8
|
+
#
|
|
9
|
+
#
|
|
8
10
|
# =Daemonize Library
|
|
9
11
|
#
|
|
10
12
|
# February. 4, 2005 Travis Whitton <whitton@atlantic.net>
|
|
@@ -132,7 +134,9 @@ module Daemonize
|
|
|
132
134
|
# Make sure all file descriptors are closed
|
|
133
135
|
ObjectSpace.each_object(IO) do |io|
|
|
134
136
|
unless [STDIN, STDOUT, STDERR].include?(io)
|
|
135
|
-
io.
|
|
137
|
+
unless io.closed?
|
|
138
|
+
io.close rescue nil
|
|
139
|
+
end
|
|
136
140
|
end
|
|
137
141
|
end
|
|
138
142
|
|
metadata
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
|
-
rubygems_version: 0.8.
|
|
2
|
+
rubygems_version: 0.8.8
|
|
3
3
|
specification_version: 1
|
|
4
4
|
name: daemons
|
|
5
5
|
version: !ruby/object:Gem::Version
|
|
6
|
-
version: 0.0
|
|
7
|
-
date: 2005-
|
|
6
|
+
version: 0.2.0
|
|
7
|
+
date: 2005-03-21
|
|
8
8
|
summary: A toolkit to convert your script to a controllable daemon
|
|
9
9
|
require_paths:
|
|
10
10
|
- lib
|
|
@@ -41,6 +41,12 @@ files:
|
|
|
41
41
|
- test/tc_main.rb
|
|
42
42
|
- test/test1.rb
|
|
43
43
|
- test/tmp
|
|
44
|
+
- examples/myserver.rb
|
|
45
|
+
- examples/myserver_crashing.rb
|
|
46
|
+
- examples/ctrl_crash.rb
|
|
47
|
+
- examples/ctrl_ontop.rb
|
|
48
|
+
- examples/ctrl_exec.rb
|
|
49
|
+
- examples/ctrl_normal.rb
|
|
44
50
|
test_files:
|
|
45
51
|
- test/tc_main.rb
|
|
46
52
|
rdoc_options: []
|