A little daemon daemonizes, but hangs the logout

I needed a little daemon thisafternoon, so I wrote one in ruby using
fork and Process.detach. It's working ok I suppose, except that when
I logout, it hangs, and I have to kill my session. It's a little
annoying, to say the least. Anyone know a better way of doing this?

Thanks, code follows
--Kyle

#!/usr/bin/ruby
#I've chopped out the bulk of the code in the Monitor class, since
it's not really relevant, and not terribly clean either.
require 'net/smtp'

class Monitor
  def _setup_signals()
    death_signals=%w{KILL QUIT STOP TERM EXIT}
    Signal.trap("HUP") do
      _setup_logfile()
      _setup_ignores()
    end
    death_signals.each do
    >signal>
      Signal.trap(signal) do
        log("Caught #{signal} signal")
        @running=false
      end
    end
  end
  
  def loop
    while @running
    end
  end
end

pid = fork do
  m=Monitor.new
  m.loop
end
Process.detach(pid)

Kyle Schmitt wrote:

I needed a little daemon thisafternoon, so I wrote one in ruby using
fork and Process.detach. It's working ok I suppose, except that when
I logout, it hangs, and I have to kill my session. It's a little
annoying, to say the least. Anyone know a better way of doing this?

IIUC, Process.detach is not what you need to start a daemon. All it does is start a ruby thread to reap the pid when the child exits, so you don't end up with zombies. If the parent process exits first, this thread is gone anyway.

Search the list for daemonize... for a classic daemon, you need to double fork, Process.setsid, chdir, disconnect from stdin/out, and probably something else I'm forgetting.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Ahh ok. It's been so long since I've written a classic daemon in C,
that when I saw a post using Process.detach I thought, wow, ruby
really _does_ make everything so easy :wink:

I'll go read, and go the classic route. Daemonize is probably a fine
nice library, but being for work, issues sometimes arise about which
extra packages are put on a server. Gobs of home-grown code are fine,
third party apps and libs are _sometimes_ frowned upon. Just one of
those things.

Thanks
--Kyle

···

On Tue, Feb 17, 2009 at 5:38 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

I needed a little daemon thisafternoon, so I wrote one in ruby using
fork and Process.detach. It's working ok I suppose, except that when

IIUC, Process.detach is not what you need to start a daemon. All it does is
start a ruby thread to reap the pid when the child exits, so you don't end
up with zombies. If the parent process exits first, this thread is gone
anyway.

Search the list for daemonize... for a classic daemon, you need to double
fork, Process.setsid, chdir, disconnect from stdin/out, and probably
something else I'm forgetting.

--
     vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Kyle Schmitt wrote:

Ahh ok. It's been so long since I've written a classic daemon in C,
that when I saw a post using Process.detach I thought, wow, ruby
really _does_ make everything so easy :wink:

I'll go read, and go the classic route.

I googled up this paper, and when I pasted it here I realised I'd
found my own copy! ha! <http://cjh.polyplex.org/software/daemon.pdf&gt;

This is Dave Lennerts classic paper on how to do it properly. It's
easy to forget things.

There is a perfectly serviceable Daemon class in lib/webrick/server.rb
as well.

You can use it as is, or as a template for your own code.

Regards,

···

--
Posted via http://www.ruby-forum.com/.

Jeff Moore wrote:

There is a perfectly serviceable Daemon class in lib/webrick/server.rb
as well.

You can use it as is, or as a template for your own code.

And there is this one from rackup (part of the rack package)

if daemonize
  if RUBY_VERSION < "1.9"
    exit if fork
    Process.setsid
    exit if fork
    Dir.chdir "/"
    File.umask 0000
    STDIN.reopen "/dev/null"
    STDOUT.reopen "/dev/null", "a"
    STDERR.reopen "/dev/null", "a"
  else
    Process.daemon
  end

  if pid
    File.open(pid, 'w'){ |f| f.write("#{Process.pid}") }
    at_exit { File.delete(pid) if File.exist?(pid) }
  end
end

···

--
Posted via http://www.ruby-forum.com/\.

Hi,

At Thu, 19 Feb 2009 23:25:20 +0900,
Brian Candler wrote in [ruby-talk:328745]:

And there is this one from rackup (part of the rack package)

if daemonize
  if RUBY_VERSION < "1.9"

Assuming it's possible to check a feature by version number is
an evil habitat. You can just do it by

  unless defined?(Process.daemon)

or, define your own Process.daemon.

  module Process
    unless defined?(daemon)
      def self.daemon(nochdir=nil, noclose=nil)
      exit! if fork
      Process.setsid
  unless nochdir
        Dir.chdir "/"
  end
  unless noclose
        STDIN.reopen "/dev/null"
        STDOUT.reopen "/dev/null", "w"
        STDERR.reopen STDOUT
        end
      end
    end
  end

···

--
Nobu Nakada

Nobuyoshi Nakada wrote:

Hi,

At Thu, 19 Feb 2009 23:25:20 +0900,
Brian Candler wrote in [ruby-talk:328745]:

And there is this one from rackup (part of the rack package)

if daemonize
  if RUBY_VERSION < "1.9"

Assuming it's possible to check a feature by version number is
an evil habitat. You can just do it by

  unless defined?(Process.daemon)

or, define your own Process.daemon.

  module Process
    unless defined?(daemon)
      def self.daemon(nochdir=nil, noclose=nil)
      exit! if fork
      Process.setsid
  unless nochdir
        Dir.chdir "/"
  end
  unless noclose
        STDIN.reopen "/dev/null"
        STDOUT.reopen "/dev/null", "w"
        STDERR.reopen STDOUT
        end
      end
    end
  end

It doesn't need to fork twice?

Also the

     File.umask 0000

line differs from Brian's version (and others I've seen).

I've never understood why the umask is needed, and in fact recently took it out of some daemons because it was causing dirs to get ceated as world writable. Why would a daemon want that?

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf wrote:

It doesn't need to fork twice?

Apparently it doesn't need to do many of the things mentioned in
the paper I quoted, like closing all other FDs.

/me sighs and mutters about re-inventing history.

causing dirs to get ceated as world writable. Why would a daemon want that?

They wouldn't - but they don't want their behaviour to depend on
how they were launched either. They should specify a permissions
mask when they create things, or set umask themselves.