| Module | Daemonize |
| In: |
lib/daemons/daemonize.rb
|
February. 4, 2005 Travis Whitton <whitton@atlantic.net>
Daemonize allows you to easily modify any existing Ruby program to run as a daemon. See README.rdoc for more details.
build the docs if you want to
The Daemonize extension module is copywrited free software by Travis Whitton <whitton@atlantic.net>. You can redistribute it under the terms specified in the COPYING file of the Ruby distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Daemonize is a module derived from Perl‘s Proc::Daemon module. This module allows you to easily modify any existing Ruby program to run as a daemon. A daemon is a process that runs in the background with no controlling terminal. Generally servers (like FTP and HTTP servers) run as daemon processes. Note, do not make the mistake that a daemon == server. Converting a program to a daemon by hand is a relatively simple process; however, this module will save you the effort of repeatedly looking up the procedure, and it will also insure that your programs are daemonized in the safest and most corrects fashion possible.
The Daemonize module does the following:
Forks a child and exits the parent process.
Becomes a session leader (which detaches the program from the controlling terminal).
Forks another child process and exits first child. This prevents the potential of acquiring a controlling terminal.
Changes the current working directory to "/".
Clears the file creation mask.
Closes file descriptors.
Using the Daemonize module is extremely simple:
require 'daemonize'
class TestDaemon
include Daemonize
def initialize
daemonize()
loop do
# do some work here
end
end
end
Daemonize was written by Travis Whitton and is based on Perl‘s Proc::Daemonize, which was written by Earl Hood. The above documentation is also partially borrowed from the Proc::Daemonize POD documentation.
| VERSION | = | "0.1.1m" |
# File lib/daemons/daemonize.rb, line 142
142: def call_as_daemon(block, logfile_name = nil, app_name = nil)
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: # child
156:
157: rd.close
158:
159: # Detach from the controlling terminal
160: unless sess_id = Process.setsid
161: raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
162: end
163:
164: # Prevent the possibility of acquiring a controlling terminal
165: #if oldmode.zero?
166: trap 'SIGHUP', 'IGNORE'
167: exit if pid = safefork
168: #end
169:
170: wr.write Process.pid
171: wr.close
172:
173: $0 = app_name if app_name
174:
175: Dir.chdir "/" # Release old working directory
176: File.umask 0000 # Insure sensible umask
177:
178: # Make sure all file descriptors are closed
179: ObjectSpace.each_object(IO) do |io|
180: unless [STDIN, STDOUT, STDERR].include?(io)
181: begin
182: unless io.closed?
183: io.close
184: end
185: rescue ::Exception
186: end
187: end
188: end
189:
190: redirect_io(logfile_name)
191:
192: block.call
193:
194: exit
195: end
196: end
This method causes the current running process to become a daemon
# File lib/daemons/daemonize.rb, line 201
201: def daemonize(logfile_name = nil, app_name = nil)
202: srand # Split rand streams between spawning and daemonized process
203: safefork and exit # Fork and exit from the parent
204:
205: # Detach from the controlling terminal
206: unless sess_id = Process.setsid
207: raise Daemons.RuntimeException.new('cannot detach from controlling terminal')
208: end
209:
210: # Prevent the possibility of acquiring a controlling terminal
211: #if oldmode.zero?
212: trap 'SIGHUP', 'IGNORE'
213: exit if pid = safefork
214: #end
215:
216: $0 = app_name if app_name
217:
218: Dir.chdir "/" # Release old working directory
219: File.umask 0000 # Insure sensible umask
220:
221: # Make sure all file descriptors are closed
222: ObjectSpace.each_object(IO) do |io|
223: unless [STDIN, STDOUT, STDERR].include?(io)
224: begin
225: unless io.closed?
226: io.close
227: end
228: rescue ::Exception
229: end
230: end
231: end
232:
233: redirect_io(logfile_name)
234:
235: #return oldmode ? sess_id : 0 # Return value is mostly irrelevant
236: return sess_id
237: end
Free file descriptors and point them somewhere sensible STDOUT/STDERR should go to a logfile
# File lib/daemons/daemonize.rb, line 244
244: def redirect_io(logfile_name)
245: begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
246:
247: if logfile_name
248: begin
249: STDOUT.reopen logfile_name, "a"
250: STDOUT.sync = true
251: rescue ::Exception
252: begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
253: end
254: else
255: begin; STDOUT.reopen "/dev/null"; rescue ::Exception; end
256: end
257:
258: begin; STDERR.reopen STDOUT; rescue ::Exception; end
259: STDERR.sync = true
260: end
Try to fork if at all possible retrying every 5 sec if the maximum process limit for the system has been reached
# File lib/daemons/daemonize.rb, line 97
97: def safefork
98: tryagain = true
99:
100: while tryagain
101: tryagain = false
102: begin
103: if pid = fork
104: return pid
105: end
106: rescue Errno::EWOULDBLOCK
107: sleep 5
108: tryagain = true
109: end
110: end
111: end
# File lib/daemons/daemonize.rb, line 115
115: def simulate(logfile_name = nil)
116: # NOTE: STDOUT and STDERR will not be redirected to the logfile, because in :ontop mode, we normally want to see the output
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: begin; STDIN.reopen "/dev/null"; rescue ::Exception; end
138: end