blue-daemons 1.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +27 -0
  5. data/LICENSE +22 -0
  6. data/README-mlanett.rdoc +8 -0
  7. data/README.rdoc +214 -0
  8. data/Rakefile +32 -0
  9. data/Releases +201 -0
  10. data/TODO +2 -0
  11. data/daemons.gemspec +27 -0
  12. data/examples/call/call.rb +57 -0
  13. data/examples/call/call.rb.log +1 -0
  14. data/examples/call/call_monitor.rb +55 -0
  15. data/examples/daemonize/daemonize.rb +27 -0
  16. data/examples/run/ctrl_crash.rb +17 -0
  17. data/examples/run/ctrl_exec.rb +16 -0
  18. data/examples/run/ctrl_exit.rb +15 -0
  19. data/examples/run/ctrl_hanging.rb +19 -0
  20. data/examples/run/ctrl_keep_pid_files.rb +17 -0
  21. data/examples/run/ctrl_monitor.rb +16 -0
  22. data/examples/run/ctrl_monitor_multiple.rb +18 -0
  23. data/examples/run/ctrl_multiple.rb +16 -0
  24. data/examples/run/ctrl_normal.rb +11 -0
  25. data/examples/run/ctrl_ontop.rb +16 -0
  26. data/examples/run/ctrl_optionparser.rb +43 -0
  27. data/examples/run/ctrl_proc.rb +25 -0
  28. data/examples/run/ctrl_proc.rb.output +121 -0
  29. data/examples/run/ctrl_proc_multiple.rb +22 -0
  30. data/examples/run/ctrl_proc_multiple.rb.output +2 -0
  31. data/examples/run/ctrl_proc_rand.rb +23 -0
  32. data/examples/run/ctrl_proc_simple.rb +17 -0
  33. data/examples/run/ctrl_slowstop.rb +16 -0
  34. data/examples/run/myserver.rb +12 -0
  35. data/examples/run/myserver_crashing.rb +14 -0
  36. data/examples/run/myserver_exiting.rb +8 -0
  37. data/examples/run/myserver_hanging.rb +21 -0
  38. data/examples/run/myserver_slowstop.rb +21 -0
  39. data/lib/daemons.rb +312 -0
  40. data/lib/daemons/application.rb +481 -0
  41. data/lib/daemons/application_group.rb +200 -0
  42. data/lib/daemons/change_privilege.rb +19 -0
  43. data/lib/daemons/cmdline.rb +121 -0
  44. data/lib/daemons/controller.rb +140 -0
  45. data/lib/daemons/daemonize.rb +182 -0
  46. data/lib/daemons/etc_extension.rb +12 -0
  47. data/lib/daemons/exceptions.rb +31 -0
  48. data/lib/daemons/monitor.rb +144 -0
  49. data/lib/daemons/pid.rb +114 -0
  50. data/lib/daemons/pidfile.rb +118 -0
  51. data/lib/daemons/pidmem.rb +19 -0
  52. data/lib/daemons/version.rb +3 -0
  53. data/setup.rb +1360 -0
  54. data/spec/pidfile_spec.rb +12 -0
  55. data/spec/spec_helper.rb +1 -0
  56. metadata +146 -0
@@ -0,0 +1,22 @@
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
+
12
+ options = {
13
+ :log_output => true,
14
+ :multiple => true,
15
+ }
16
+
17
+
18
+ Daemons.run_proc('ctrl_proc_multiple.rb', options) do
19
+ puts "hello"
20
+ sleep(5)
21
+ puts "done"
22
+ end
@@ -0,0 +1,23 @@
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
+
10
+ require 'daemons'
11
+
12
+
13
+ Daemons.run_proc('myscript') do
14
+ loop do
15
+ file = File.open('/tmp/myscript.log', 'a')
16
+ file.write(Random.rand) # breaks without seeding
17
+ # file.write(Random.new.rand) # works without seeding
18
+ # file.write(rand) # also works, but this is Kernel.rand() so its different
19
+ file.write("\n")
20
+ file.close()
21
+ sleep 2
22
+ end
23
+ end
@@ -0,0 +1,17 @@
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
+
12
+ Daemons.run_proc('ctrl_proc_simple.rb') do
13
+ loop do
14
+ puts 'ping from proc!'
15
+ sleep(3)
16
+ end
17
+ end
@@ -0,0 +1,16 @@
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
+ #:force_kill_waittime => 40
13
+ #:force_kill_waittime => -1 # do not wait before killing -9
14
+ }
15
+
16
+ Daemons.run(File.join(File.dirname(__FILE__), 'myserver_slowstop.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 10 seconds...'
9
+
10
+ sleep(10)
11
+
12
+ puts 'CRASH!'
13
+ raise 'CRASH!'
14
+ end
@@ -0,0 +1,8 @@
1
+ loop do
2
+ puts 'ping from myserver.rb!'
3
+ puts 'this example server will exit in 3 seconds...'
4
+
5
+ sleep(3)
6
+
7
+ Process.exit
8
+ end
@@ -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
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+
4
+ # This is myserver_slowstop.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
+ # simulate the slow stopping
13
+ sleep(10)
14
+
15
+ exit
16
+ }
17
+
18
+ loop do
19
+ puts 'ping from myserver.rb!'
20
+ sleep(3)
21
+ end
@@ -0,0 +1,312 @@
1
+ require 'optparse'
2
+ require 'optparse/time'
3
+
4
+
5
+ require 'daemons/pidfile'
6
+ require 'daemons/cmdline'
7
+ require 'daemons/exceptions'
8
+ require 'daemons/monitor'
9
+
10
+ require 'daemons/application'
11
+ require 'daemons/application_group'
12
+ require 'daemons/controller'
13
+ require "daemons/version"
14
+
15
+
16
+ # All functions and classes that Daemons provides reside in this module.
17
+ #
18
+ # Daemons is normally invoked by one of the following four ways:
19
+ #
20
+ # 1. <tt>Daemons.run(script, options)</tt>:
21
+ # This is used in wrapper-scripts that are supposed to control other ruby scripts or
22
+ # external applications. Control is completely passed to the daemons library.
23
+ # Such wrapper script need to be invoked with command line options like 'start' or 'stop'
24
+ # to do anything useful.
25
+ #
26
+ # 2. <tt>Daemons.run_proc(app_name, options) { (...) }</tt>:
27
+ # This is used in wrapper-scripts that are supposed to control a proc.
28
+ # Control is completely passed to the daemons library.
29
+ # Such wrapper scripts need to be invoked with command line options like 'start' or 'stop'
30
+ # to do anything useful.
31
+ #
32
+ # 3. <tt>Daemons.call(options) { block }</tt>:
33
+ # Execute the block in a new daemon. <tt>Daemons.call</tt> will return immediately
34
+ # after spawning the daemon with the new Application object as a return value.
35
+ #
36
+ # 4. <tt>Daemons.daemonize(options)</tt>:
37
+ # Daemonize the currently runnig process, i.e. the calling process will become a daemon.
38
+ #
39
+ # == What does daemons internally do with my daemons?
40
+ # *or*:: why do my daemons crash when they try to open a file?
41
+ # *or*:: why can I not see any output from the daemon on the console (when using for example +puts+)?
42
+ #
43
+ # From a technical aspect of view, daemons does the following when creating a daemon:
44
+ #
45
+ # 1. Forks a child (and exits the parent process, if needed)
46
+ # 2. Becomes a session leader (which detaches the program from
47
+ # the controlling terminal).
48
+ # 3. Forks another child process and exits first child. This prevents
49
+ # the potential of acquiring a controlling terminal.
50
+ # 4. Changes the current working directory to "/".
51
+ # 5. Clears the file creation mask (sets +umask+ to 0000).
52
+ # 6. Closes file descriptors (reopens +STDOUT+ and +STDERR+ to point to a logfile if
53
+ # possible).
54
+ #
55
+ # So what does this mean for your daemons:
56
+ # - the current directory is '/'
57
+ # - you cannot receive any input from the console (for example no +gets+)
58
+ # - you cannot output anything from the daemons with +puts+/+print+ unless a logfile is used
59
+ #
60
+ # == How do PidFiles work? Where are they stored?
61
+ #
62
+ # Also, you are maybe interested in reading the documentation for the class PidFile.
63
+ # There you can find out about how Daemons works internally and how and where the so
64
+ # called <i>PidFiles</i> are stored.
65
+ #
66
+ module Daemons
67
+
68
+ require 'daemons/daemonize'
69
+
70
+
71
+ # Passes control to Daemons.
72
+ # This is used in wrapper-scripts that are supposed to control other ruby scripts or
73
+ # external applications. Control is completely passed to the daemons library.
74
+ # Such wrapper script should be invoked with command line options like 'start' or 'stop'
75
+ # to do anything useful.
76
+ #
77
+ # +script+:: This is the path to the script that should be run as a daemon.
78
+ # Please note that Daemons runs this script with <tt>load <script></tt>.
79
+ # Also note that Daemons cannot detect the directory in which the controlling
80
+ # script resides, so this has to be either an absolute path or you have to run
81
+ # the controlling script from the appropriate directory. Your script name should not
82
+ # end with _monitor because that name is reserved for a monitor process which is
83
+ # there to restart your daemon if it crashes.
84
+ #
85
+ # +options+:: A hash that may contain one or more of the options listed below
86
+ #
87
+ # === Options:
88
+ # <tt>:app_name</tt>:: The name of the application. This will be
89
+ # used to contruct the name of the pid files
90
+ # and log files. Defaults to the basename of
91
+ # the script.
92
+ # <tt>:ARGV</tt>:: An array of strings containing parameters and switches for Daemons.
93
+ # This includes both parameters for Daemons itself and the controlled scripted.
94
+ # These are assumed to be separated by an array element '--', .e.g.
95
+ # ['start', 'f', '--', 'param1_for_script', 'param2_for_script'].
96
+ # If not given, ARGV (the parameters given to the Ruby process) will be used.
97
+ # <tt>:dir_mode</tt>:: Either <tt>:script</tt> (the directory for writing the pid files to
98
+ # given by <tt>:dir</tt> is interpreted relative
99
+ # to the script location given by +script+, the default) or <tt>:normal</tt> (the directory given by
100
+ # <tt>:dir</tt> is interpreted as a (absolute or relative) path) or <tt>:system</tt>
101
+ # (<tt>/var/run</tt> is used as the pid file directory)
102
+ #
103
+ # <tt>:dir</tt>:: Used in combination with <tt>:dir_mode</tt> (description above)
104
+ # <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
105
+ # same time
106
+ # <tt>:ontop</tt>:: When given (i.e. set to true), stay on top, i.e. do not daemonize the application
107
+ # (but the pid-file and other things are written as usual)
108
+ # <tt>:mode</tt>:: <tt>:load</tt> Load the script with <tt>Kernel.load</tt>;
109
+ # note that :stop_proc only works for the :load (and :proc) mode.
110
+ # <tt>:exec</tt> Execute the script file with <tt>Kernel.exec</tt>
111
+ # <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
112
+ # pid-file directory if the application exits due to an uncaught exception
113
+ # <tt>:monitor</tt>:: Monitor the programs and restart crashed instances
114
+ # <tt>:log_dir</tt>:: A specific directory to put the log files into (when not given, resort to the default
115
+ # location as derived from the :dir_mode and :dir options
116
+ # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named '[app_name].output' in the pid-file directory
117
+ # <tt>:keep_pid_files</tt>:: When given do not delete lingering pid-files (files for which the process is no longer running).
118
+ # <tt>:hard_exit</tt>:: When given use exit! to end a daemons instead of exit (this will for example
119
+ # not call at_exit handlers).
120
+ # <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)
121
+ #
122
+ # -----
123
+ #
124
+ # === Example:
125
+ # options = {
126
+ # :app_name => "my_app",
127
+ # :ARGV => ['start', '-f', '--', 'param_for_myscript']
128
+ # :dir_mode => :script,
129
+ # :dir => 'pids',
130
+ # :multiple => true,
131
+ # :ontop => true,
132
+ # :mode => :exec,
133
+ # :backtrace => true,
134
+ # :monitor => true
135
+ # }
136
+ #
137
+ # Daemons.run(File.join(File.dirname(__FILE__), 'myscript.rb'), options)
138
+ #
139
+ def run(script, options = {})
140
+ options[:script] = script
141
+ @controller = Controller.new(options, options[:ARGV] || ARGV)
142
+
143
+ @controller.catch_exceptions {
144
+ @controller.run
145
+ }
146
+
147
+ # I don't think anybody will ever use @group, as this location should not be reached under non-error conditions
148
+ @group = @controller.group
149
+ end
150
+ module_function :run
151
+
152
+
153
+ # Passes control to Daemons.
154
+ # This function does the same as Daemons.run except that not a script but a proc
155
+ # will be run as a daemon while this script provides command line options like 'start' or 'stop'
156
+ # and the whole pid-file management to control the proc.
157
+ #
158
+ # +app_name+:: The name of the application. This will be
159
+ # used to contruct the name of the pid files
160
+ # and log files. Defaults to the basename of
161
+ # the script.
162
+ #
163
+ # +options+:: A hash that may contain one or more of the options listed in the documentation for Daemons.run
164
+ #
165
+ # A block must be given to this function. The block will be used as the :proc entry in the options hash.
166
+ #
167
+ # -----
168
+ #
169
+ # === Example:
170
+ #
171
+ # Daemons.run_proc('myproc.rb') do
172
+ # loop do
173
+ # accept_connection()
174
+ # read_request()
175
+ # send_response()
176
+ # close_connection()
177
+ # end
178
+ # end
179
+ #
180
+ def run_proc(app_name, options = {}, &block)
181
+ options[:app_name] = app_name
182
+ options[:mode] = :proc
183
+ options[:proc] = block
184
+
185
+ # we do not have a script location so the the :script :dir_mode cannot be used, change it to :normal
186
+ if [nil, :script].include? options[:dir_mode]
187
+ options[:dir_mode] = :normal
188
+ options[:dir] ||= File.expand_path('.')
189
+ end
190
+
191
+ @controller = Controller.new(options, options[:ARGV] || ARGV)
192
+
193
+ @controller.catch_exceptions {
194
+ @controller.run
195
+ }
196
+
197
+ # I don't think anybody will ever use @group, as this location should not be reached under non-error conditions
198
+ @group = @controller.group
199
+ end
200
+ module_function :run_proc
201
+
202
+
203
+ # Execute the block in a new daemon. <tt>Daemons.call</tt> will return immediately
204
+ # after spawning the daemon with the new Application object as a return value.
205
+ #
206
+ # +app_name+:: The name of the application.
207
+ #
208
+ # +options+:: A hash that may contain one or more of the options listed below
209
+ #
210
+ # +block+:: The block to call in the daemon.
211
+ #
212
+ # === Options:
213
+ # <tt>:multiple</tt>:: Specifies whether multiple instances of the same script are allowed to run at the
214
+ # same time
215
+ # <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
216
+ # <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
217
+ # pid-file directory if the application exits due to an uncaught exception
218
+ # -----
219
+ #
220
+ # === Example:
221
+ # options = {
222
+ # :app_name => "myproc",
223
+ # :backtrace => true,
224
+ # :monitor => true,
225
+ # :ontop => true
226
+ # }
227
+ #
228
+ # Daemons.call(options) begin
229
+ # # Server loop:
230
+ # loop {
231
+ # conn = accept_conn()
232
+ # serve(conn)
233
+ # }
234
+ # end
235
+ #
236
+ def call(options = {}, &block)
237
+ unless block_given?
238
+ raise "Daemons.call: no block given"
239
+ end
240
+
241
+ options[:proc] = block
242
+ options[:mode] = :proc
243
+
244
+ options[:app_name] ||= 'proc'
245
+
246
+ @group ||= ApplicationGroup.new(options[:app_name], options)
247
+
248
+ new_app = @group.new_application(options)
249
+ new_app.start
250
+
251
+ return new_app
252
+ end
253
+ module_function :call
254
+
255
+
256
+ # Daemonize the currently runnig process, i.e. the calling process will become a daemon.
257
+ #
258
+ # +options+:: A hash that may contain one or more of the options listed below
259
+ #
260
+ # === Options:
261
+ # <tt>:ontop</tt>:: When given, stay on top, i.e. do not daemonize the application
262
+ # <tt>:backtrace</tt>:: Write a backtrace of the last exceptions to the file '[app_name].log' in the
263
+ # pid-file directory if the application exits due to an uncaught exception
264
+ # <tt>:app_name</tt>:: The name of the application. This will be
265
+ # used to contruct the name of the pid files
266
+ # and log files. Defaults to the basename of
267
+ # the script.
268
+ # <tt>:dir_mode</tt>:: Either <tt>:script</tt> (the directory for writing files to
269
+ # given by <tt>:dir</tt> is interpreted relative
270
+ # to the script location given by +script+, the default) or <tt>:normal</tt> (the directory given by
271
+ # <tt>:dir</tt> is interpreted as a (absolute or relative) path) or <tt>:system</tt>
272
+ # (<tt>/var/run</tt> is used as the file directory)
273
+ #
274
+ # <tt>:dir</tt>:: Used in combination with <tt>:dir_mode</tt> (description above)
275
+ # <tt>:log_dir</tt>:: A specific directory to put the log files into (when not given, resort to the default
276
+ # location as derived from the :dir_mode and :dir options
277
+ # <tt>:log_output</tt>:: When given (i.e. set to true), redirect both STDOUT and STDERR to a logfile named '[app_name].output' in the pid-file directory
278
+ # -----
279
+ #
280
+ # === Example:
281
+ # options = {
282
+ # :backtrace => true,
283
+ # :ontop => true,
284
+ # :log_output => true
285
+ # }
286
+ #
287
+ # Daemons.daemonize(options)
288
+ #
289
+ # # Server loop:
290
+ # loop {
291
+ # conn = accept_conn()
292
+ # puts "some text which goes to the output logfile"
293
+ # serve(conn)
294
+ # }
295
+ #
296
+ def daemonize(options = {})
297
+ options[:script] ||= File.basename(__FILE__)
298
+
299
+ @group ||= ApplicationGroup.new(options[:app_name] || options[:script], options)
300
+
301
+ @group.new_application(:mode => :none).start
302
+ end
303
+ module_function :daemonize
304
+
305
+ # Return the internal ApplicationGroup instance.
306
+ def group; @group; end
307
+ module_function :group
308
+
309
+ # Return the internal Controller instance.
310
+ def controller; @controller; end
311
+ module_function :controller
312
+ end