proper way to daemonize

T

Tim Pease

module Process
def self.daemon( nochdir = nil, noclose = nil )
exit if fork # Parent exits, child continues.
Process.setsid # Become session leader.
exit if fork # Zap session leader.

unless nochdir
Dir.chdir "/" # Release old working directory.
end

File.umask 0000 # Ensure sensible umask. Adjust as needed.

unless noclose
STDIN.reopen "/dev/null" # Free file descriptors and
STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
STDERR.reopen '/dev/null', 'a'
end

return 0
end
end


This is the standard code to daemonize a process. The use of "exit"
bothers me slightly, as it will call all "at_exit" handlers in the
parent. I do not believe this is the desired behavior; the "at_exit"
handlers will free resources that the daemonized process might need.
Instead, "exit!" should be used to prevent "at_exit" handlers from
being called.

Any thoughts about this subtle change? Are there any undesirable side
effects that arise from using exit! instead of exit ?

Blessings,
TwP
 
G

Gary Wright

This is the standard code to daemonize a process. The use of "exit"
bothers me slightly, as it will call all "at_exit" handlers in the
parent. I do not believe this is the desired behavior; the "at_exit"
handlers will free resources that the daemonized process might need.

What resources are you talking about? By the time exit is called, the
process has already been duplicated. The child process won't be
affected
by anything the parent does during via at_exit processing (at least
with respect to Ruby object resources).
 
J

James Gray

What resources are you talking about? By the time exit is called, the
process has already been duplicated. The child process won't be =20
affected
by anything the parent does during via at_exit processing (at least
with respect to Ruby object resources).

But if that at_exit() handler deletes a file or something=85

Anyway, I do use exit!() in my daemonize() method.

James Edward Gray II=
 
G

Gary Wright

But if that at_exit() handler deletes a file or something=85


Well, that is why I put the caveat about 'Ruby object resources'.
Isn't it fair to assume the at_exit code isn't actively hostile? :)

If you've got at_exit() code that is trashing external resources that =20=

are used by a child process, that is a bug to be fixed I think rather =20=

than a bug to be obscured via exit!=
 
T

Tim Pease

Well, that is why I put the caveat about 'Ruby object resources'.
Isn't it fair to assume the at_exit code isn't actively hostile? :)

If you've got at_exit() code that is trashing external resources that are
used by a child process, that is a bug to be fixed I think rather than a = bug
to be obscured via exit!

Yes, I am using an at_exit hook to close out file descriptors used by
loggers. Part of this close out process is writing out some diagnostic
messages to the loggers. These at_exit hooks need to be called when
the child process exits, not when the parent process exits.

The two solutions are:

1) daemonize is the VERY FIRST thing the program should do before any
initialization is run
2) daemonize should use exit! if initialization needs to be performed
before daemonizing

Anyway, it sounds like James is using exit! without ill affect. /me
heads in that direction.

Blessings,
TwP
 
R

Robert Dober

Well, that is why I put the caveat about 'Ruby object resources'.
Isn't it fair to assume the at_exit code isn't actively hostile? :)
Well I do see the smiley but still want to point out that "passively
hostile" might be bad enough, actually pretty bad!
If you've got at_exit() code that is trashing external resources that are
used by a child process, that is a bug to be fixed I think rather than a = bug
to be obscured via exit!
This is a good point though, I guess bombing in the child might indeed
be the best way to find out what is conceptually wrong, but I am quite
unexperienced with this kind of code in Ruby. OTOH are not most of us?

Cheers
Robert



--=20
Si tu veux construire un bateau ...
Ne rassemble pas des hommes pour aller chercher du bois, pr=E9parer des
outils, r=E9partir les t=E2ches, all=E9ger le travail=85 mais enseigne aux
gens la nostalgie de l=92infini de la mer.

If you want to build a ship, don=92t herd people together to collect
wood and don=92t assign them tasks and work, but rather teach them to
long for the endless immensity of the sea.
 
E

Eric Hodel

# ...

This is the standard code to daemonize a process. The use of "exit"
bothers me slightly, as it will call all "at_exit" handlers in the
parent. I do not believe this is the desired behavior; the "at_exit"
handlers will free resources that the daemonized process might need.
Instead, "exit!" should be used to prevent "at_exit" handlers from
being called.

Any thoughts about this subtle change? Are there any undesirable side
effects that arise from using exit! instead of exit ?

Why not just:

require 'webrick/server'

WEBrick::Dameon.start

It has exit! and all that built-in.
 
T

Tim Pease

Why not just:

require 'webrick/server'

WEBrick::Dameon.start

It has exit! and all that built-in.

Eric, if I had half your brain I'd be twice as smart. Didn't even
think to look through the stdlibs.

Sinatra and Rails use the plain old "exit" in their flavor of the
daemon method. This is causing issues with closing out log files
prematurely. Just getting a consensus from the wider ruby community
about the _correct_ behavior.

Blessings,
TwP
 
J

James Gray

Eric, if I had half your brain I'd be twice as smart. Didn't even
think to look through the stdlibs.

As of Ruby 1.9 Process.daemon() is a core method. Just one more
reason 1.9 rocks. :)

James Edward Gray II
 
J

James Gray

Well, that is why I put the caveat about 'Ruby object resources'.
Isn't it fair to assume the at_exit code isn't actively hostile? :)

If you've got at_exit() code that is trashing external resources =20
that are used by a child process, that is a bug to be fixed I think =20=
rather than a bug to be obscured via exit!

Seems like Tim has a pretty decent example where the behavior doesn't =20=

feel buggy.

Basically, I view it this way. The exit() calls in a daemonize() =20
method aren't the typical usage. Normally, exit() is used to end a =20
process. Our process isn't really ending though so much as =20
transitioning into a different kind of process. exit() is just an =20
implementation detail of how that transition occurs. As such, exit!() =20=

feels more correct to me because I don't want to go through a shutdown =20=

sequence of the original process, I just want the first to immediately =20=

cease to exist while the second takes over for it.

That's all just my opinion though. Feel free to ignore.

James Edward Gray II
 
G

Gary Wright

Seems like Tim has a pretty decent example where the behavior
doesn't feel buggy.

I wouldn't call it buggy, but calling at_exit in a process that
shouldn't execute the block seems premature. Better to wait and call
it in the forked child process, I think.

It looks like 1.9's Process.daemon uses exit! and it doesn't look like
it does a double-fork which is a best-practice sort of thing (in order
to avoid acquiring a new controlling terminal). I suppose I should
open a ticket...

Gary Wright
 
J

Jeff Moore

It looks like 1.9's Process.daemon uses exit! and it doesn't look like
it does a double-fork which is a best-practice sort of thing (in order
to avoid acquiring a new controlling terminal). I suppose I should
open a ticket...

Gary Wright

Something like this perhaps?

def RDaemon.daemon(&block)
unless fork
Process::setsid
unless fork
Dir::chdir('/')
File::umask(0)
STDIN.reopen("/dev/null")
STDOUT.reopen("/dev/null", "a") unless $DEBUG
STDERR.reopen("/dev/null", "a") unless $DEBUG
loop do
yield
end
end
end
exit!(0)
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top