Proper way to daemonize


#1

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


#2

On Apr 24, 2009, at 11:11 AM, Tim P. wrote:

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).


#3

On Apr 24, 2009, at 11:01 AM, Gary W. wrote:

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…

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

James Edward G. II


#4

On Apr 24, 2009, at 12:11 PM, James G. wrote:

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).

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

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? :slight_smile:

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!


#5

On Fri, Apr 24, 2009 at 10:40 AM, Gary W. removed_email_address@domain.invalid wrote:

handlers will free resources that the daemonized process might need.
Isn’t it fair to assume the at_exit code isn’t actively hostile? :slight_smile:

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


#6

On Apr 24, 2009, at 08:11, Tim P. wrote:

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.


#7

On Fri, Apr 24, 2009 at 12:46 PM, Eric H. removed_email_address@domain.invalid
wrote:

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


#8

On Apr 24, 2009, at 2:07 PM, Tim P. wrote:

Instead, “exit!” should be used to prevent “at_exit” handlers from
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.

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

James Edward G. II


#9

On Fri, Apr 24, 2009 at 6:40 PM, Gary W. removed_email_address@domain.invalid wrote:

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? :slight_smile:
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


Si tu veux construire un bateau …
Ne rassemble pas des hommes pour aller chercher du bois, préparer des
outils, répartir les tâches, alléger le travail… mais enseigne aux
gens la nostalgie de l’infini de la mer.

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


#10

On Apr 24, 2009, at 11:40 AM, Gary W. wrote:

parent. I do not believe this is the desired behavior; the

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

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? :slight_smile:

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!

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

Basically, I view it this way. The exit() calls in a daemonize()
method aren’t the typical usage. Normally, exit() is used to end a
process. Our process isn’t really ending though so much as
transitioning into a different kind of process. exit() is just an
implementation detail of how that transition occurs. As such, exit!()
feels more correct to me because I don’t want to go through a shutdown
sequence of the original process, I just want the first to immediately
cease to exist while the second takes over for it.

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

James Edward G. II


#11

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 W.

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


#12

On Apr 24, 2009, at 3:17 PM, James G. wrote:

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 W.