Skip to content

Instantly share code, notes, and snippets.

@mynameisrufus
Created November 17, 2011 06:09
Show Gist options
  • Select an option

  • Save mynameisrufus/1372491 to your computer and use it in GitHub Desktop.

Select an option

Save mynameisrufus/1372491 to your computer and use it in GitHub Desktop.

Revisions

  1. mynameisrufus revised this gist Mar 15, 2012. 1 changed file with 125 additions and 0 deletions.
    125 changes: 125 additions & 0 deletions simple_daemon.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,125 @@
    #!/usr/bin/env ruby
    # == Double-forking Unix daemon
    #
    # Author:: Rufus Post (mailto:rufuspost@gmail.com)
    #
    # === How does it work?
    #
    # According to Stevens's Advanced Programming in the UNIX Environment
    # chapter 13, this is the procedure to make a well-behaved Unix daemon:
    #
    # Fork and have the parent exit. This makes the shell or boot script
    # think the command is done. Also, the child process is guaranteed not
    # to be a process group leader (a prerequisite for setsid next)
    # Call setsid to create a new session. This does three things:
    # * The process becomes a session leader of a new session
    # * The process becomes the process group leader of a new process group
    # * The process has no controlling terminal
    #
    # Optionally fork again and have the parent exit. This guarantes that
    # the daemon is not a session leader nor can it acquire a controlling
    # terminal (under SVR4)
    #
    # grandparent - the current process
    # \_ parent - exits immediately
    # \_ simple daemon - writes out its pid to file
    #
    # Change the current working directory to / to avoid interfering with
    # mounting and unmounting. By default don't bother to chdir("/") here
    # because we might to run inside APP_ROOT.
    #
    # Set file mode creation mask to 000 to allow creation of files with any
    # required permission later. By default umask is whatever was set by the
    # parent process at startup and can be set in config.ru and config_file,
    # so making it 0000 and potentially exposing sensitive log data can be
    # bad policy.
    #
    # Close unneeded file descriptors inherited from the parent (there is no
    # controlling terminal anyway): stdout, stderr, and stdin.
    #
    # Nowadays there is a file to track the PID which is used heavily by
    # Linux distribution boot scripts. Be sure to write out the PID of the
    # grandchild, either the return value of the second fork (step 3) or the
    # value of getpid() after step 3.
    #
    class SimpleDaemon
    # In the directory where you want your daemon add a git submodule to
    # your project and create a daemon launcher script:
    #
    # #!/usr/bin/env ruby
    #
    # require 'simple_daemon'
    #
    # $0 = "my daemon"
    #
    # SimpleDaemon.daemonize! ARGV[0], ARGV[1], ARGV[2]
    #
    # loop do
    # sleep 5
    # puts "tick"
    # sleep 5
    # puts "tock"
    # end
    #
    # make your script executable and run:
    #
    # $ chmod +x launcher
    # $ launcher tmp/daemon.pid log/daemon.stdout.log log/daemon.stderr.log
    #
    # check that it is running by with the following:
    #
    # $ ps aux | grep "my daemon"
    #
    #
    def self.daemonize! pidfile, out = '/dev/null', err = '/dev/null', safe = true
    raise 'First fork failed' if (pid = fork) == -1
    exit unless pid.nil?
    Process.setsid
    raise 'Second fork failed' if (pid = fork) == -1
    exit unless pid.nil?
    kill pidfile
    write Process.pid, pidfile
    unless safe
    Dir.chdir '/'
    File.umask 0000
    end
    redirect out, err
    end

    # Attempts to write the pid of the forked process to the pid file.
    # Kills process if write unsuccesfull.
    def self.write pid, pidfile
    File.open pidfile, "w" do |f|
    f.write pid
    f.close
    end
    $stdout.puts "Daemon running with pid: #{pid}"
    rescue ::Exception => e
    raise "While writing the PID to file, unexpected #{e.class}: #{e}"
    end

    # Try and read the existing pid from the pid file and signal HUP to
    # process.
    def self.kill pidfile
    opid = open(pidfile).read.strip.to_i
    Process.kill "HUP", opid
    rescue TypeError
    $stdout.puts "#{pidfile} was empty: TypeError"
    rescue Errno::ENOENT
    $stdout.puts "#{pidfile} did not exist: Errno::ENOENT"
    rescue Errno::ESRCH
    $stdout.puts "The process #{opid} did not exist: Errno::ESRCH"
    rescue Errno::EPERM
    raise "Lack of privileges to manage the process #{opid}: Errno::EPERM"
    rescue ::Exception => e
    raise "While signaling the PID, unexpected #{e.class}: #{e}"
    end

    # Redirect file descriptors inherited from the parent.
    def self.redirect out, err
    $stdin.reopen '/dev/null'
    $stdout.reopen File.new(out, "a")
    $stderr.reopen File.new(err, "a")
    $stdout.sync = $stderr.sync = true
    end
    end
  2. mynameisrufus revised this gist Mar 15, 2012. 2 changed files with 2 additions and 110 deletions.
    2 changes: 2 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    tmp
    log
    doc
    daemon
    *.swp
    110 changes: 0 additions & 110 deletions simple_ruby_daemon.rb
    Original file line number Diff line number Diff line change
    @@ -1,110 +0,0 @@
    #!/usr/bin/env ruby
    # == Simple Daemon
    #
    # A simple ruby daemon that you copy and change as needed.
    #
    # === How does it work?
    #
    # All this program does is fork the current process (creates a copy of
    # itself) then exits, the fork (child process) then goes on to run your
    # daemon code. In this example we are just running a while loop with a
    # that outputs 'tick' and 'tock'.
    #
    # Most of the code is dedicated to managing a pid file. We want a pid
    # file so we can use a monitoring tool to make sure our daemon keeps
    # running.
    #
    # === Why?
    #
    # Writing a daemon sounds hard but as you can see is not that
    # complicated, so lets strip away the magic and just write some ruby.
    #
    # === Usage
    #
    # You can run this daemon by running:
    #
    # $ ./simple_ruby_daemon.rb
    #
    # or with arguments:
    #
    # $ ./simple_ruby_daemon.rb tmp/daemon.pid log/daemon.stdout.log log/daemon.stderr.log
    #
    # check that it is running by running the following:
    #
    # $ ps aux | grep "simple ruby daemon"
    #
    # Author:: Rufus Post (mailto:rufuspost@gmail.com)
    class SimpleDaemon
    # Checks to see if the current process is the child process and if not
    # will update the pid file with the child pid.
    def self.start pid, pidfile, outfile, errfile
    unless pid.nil?
    redirect outfile, errfile
    raise "Fork failed" if pid == -1
    write pid, pidfile if kill pidfile
    exit
    else
    redirect outfile, errfile
    end
    end

    # Attempts to write the pid of the forked process to the pid file.
    def self.write pid, pidfile
    File.open pidfile, "w" do |f|
    f.write pid
    f.close
    end
    rescue ::Exception => e
    $stderr.puts "While writing the PID to file, unexpected #{e.class}: #{e}"
    Process.kill "HUP", pid
    end

    # Try and read the existing pid from the pid file and signal the
    # process. Returns true for a non blocking status.
    def self.kill pidfile
    opid = open(pidfile).read.strip.to_i
    Process.kill "HUP", opid
    true
    rescue Errno::ENOENT
    $stdout.puts "#{pidfile} did not exist: Errno::ENOENT"
    true
    rescue Errno::ESRCH
    $stdout.puts "The process #{opid} did not exist: Errno::ESRCH"
    true
    rescue Errno::EPERM
    $stderr.puts "Lack of privileges to manage the process #{opid}: Errno::EPERM"
    false
    rescue ::Exception => e
    $stderr.puts "While signaling the PID, unexpected #{e.class}: #{e}"
    false
    end

    # Send stdout and stderr to log files for the child process
    def self.redirect outfile, errfile
    $stdin.reopen '/dev/null'
    out = File.new outfile, "a"
    err = File.new errfile, "a"
    $stdout.reopen out
    $stderr.reopen err
    $stdout.sync = $stderr.sync = true
    end
    end

    # Process name of your daemon
    $0 = "simple ruby daemon"

    # Spawn a deamon
    SimpleDaemon.start fork, (ARGV[0] || 'tmp/daemon.pid'), (ARGV[1] || 'log/daemon.stdout.log'), (ARGV[2] || 'log/daemon.stderr.log')

    # Set up signals for our daemon, for now they just exit the process.
    Signal.trap("HUP") { $stdout.puts "SIGHUP and exit"; exit }
    Signal.trap("INT") { $stdout.puts "SIGINT and exit"; exit }
    Signal.trap("QUIT") { $stdout.puts "SIGQUIT and exit"; exit }

    # Remove this loop and replace with your own daemon logic.
    loop do
    sleep 5
    puts "tick"
    sleep 5
    puts "tock"
    end
  3. mynameisrufus revised this gist Mar 14, 2012. 2 changed files with 16 additions and 8 deletions.
    3 changes: 3 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    tmp
    log
    *.swp
    21 changes: 13 additions & 8 deletions simple_ruby_daemon.rb
    Original file line number Diff line number Diff line change
    @@ -8,7 +8,7 @@
    # All this program does is fork the current process (creates a copy of
    # itself) then exits, the fork (child process) then goes on to run your
    # daemon code. In this example we are just running a while loop with a
    # 1 second sleep.
    # that outputs 'tick' and 'tock'.
    #
    # Most of the code is dedicated to managing a pid file. We want a pid
    # file so we can use a monitoring tool to make sure our daemon keeps
    @@ -25,22 +25,23 @@
    #
    # $ ./simple_ruby_daemon.rb
    #
    # or with an optional pid file location as its first argument:
    # or with arguments:
    #
    # $ ./simple_ruby_daemon.rb tmp/simple_ruby_daemon.pid
    # $ ./simple_ruby_daemon.rb tmp/daemon.pid log/daemon.stdout.log log/daemon.stderr.log
    #
    # check that it is running by running the following:
    #
    # $ ps aux | grep simple_ruby_daemon
    # $ ps aux | grep "simple ruby daemon"
    #
    # Author:: Rufus Post (mailto:rufuspost@gmail.com)
    class SimpleDaemon
    # Checks to see if the current process is the child process and if not
    # will update the pid file with the child pid.
    def self.start pid, pidfile, outfile, errfile
    unless pid.nil?
    redirect outfile, errfile
    raise "Fork failed" if pid == -1
    write pid, pidfile if kill pid, pidfile
    write pid, pidfile if kill pidfile
    exit
    else
    redirect outfile, errfile
    @@ -51,6 +52,7 @@ def self.start pid, pidfile, outfile, errfile
    def self.write pid, pidfile
    File.open pidfile, "w" do |f|
    f.write pid
    f.close
    end
    rescue ::Exception => e
    $stderr.puts "While writing the PID to file, unexpected #{e.class}: #{e}"
    @@ -59,7 +61,7 @@ def self.write pid, pidfile

    # Try and read the existing pid from the pid file and signal the
    # process. Returns true for a non blocking status.
    def self.kill(pid, pidfile)
    def self.kill pidfile
    opid = open(pidfile).read.strip.to_i
    Process.kill "HUP", opid
    true
    @@ -92,7 +94,7 @@ def self.redirect outfile, errfile
    $0 = "simple ruby daemon"

    # Spawn a deamon
    SimpleDaemon.start fork, (ARGV[0] || '/tmp/deamon.pid'), (ARGV[1] || '/tmp/daemon.stdout.log'), (ARGV[2] || '/tmp/daemon.stderr.log')
    SimpleDaemon.start fork, (ARGV[0] || 'tmp/daemon.pid'), (ARGV[1] || 'log/daemon.stdout.log'), (ARGV[2] || 'log/daemon.stderr.log')

    # Set up signals for our daemon, for now they just exit the process.
    Signal.trap("HUP") { $stdout.puts "SIGHUP and exit"; exit }
    @@ -101,5 +103,8 @@ def self.redirect outfile, errfile

    # Remove this loop and replace with your own daemon logic.
    loop do
    sleep 1
    sleep 5
    puts "tick"
    sleep 5
    puts "tock"
    end
  4. mynameisrufus revised this gist Mar 5, 2012. 1 changed file with 19 additions and 7 deletions.
    26 changes: 19 additions & 7 deletions simple_ruby_daemon.rb
    Original file line number Diff line number Diff line change
    @@ -37,16 +37,18 @@
    class SimpleDaemon
    # Checks to see if the current process is the child process and if not
    # will update the pid file with the child pid.
    def self.start(pid, pidfile)
    def self.start pid, pidfile, outfile, errfile
    unless pid.nil?
    raise "Fork failed" if pid == -1
    write(pid, pidfile) if kill(pid, pidfile)
    write pid, pidfile if kill pid, pidfile
    exit
    else
    redirect outfile, errfile
    end
    end

    # Attempts to write the pid of the forked process to the pid file.
    def self.write(pid, pidfile)
    def self.write pid, pidfile
    File.open pidfile, "w" do |f|
    f.write pid
    end
    @@ -74,18 +76,28 @@ def self.kill(pid, pidfile)
    $stderr.puts "While signaling the PID, unexpected #{e.class}: #{e}"
    false
    end

    # Send stdout and stderr to log files for the child process
    def self.redirect outfile, errfile
    $stdin.reopen '/dev/null'
    out = File.new outfile, "a"
    err = File.new errfile, "a"
    $stdout.reopen out
    $stderr.reopen err
    $stdout.sync = $stderr.sync = true
    end
    end

    # Process name of your daemon
    $0 = "simple ruby daemon"

    # Spawn a deamon
    SimpleDaemon.start fork, (ARGV.first || '/tmp/simple_ruby_deamon.pid')
    SimpleDaemon.start fork, (ARGV[0] || '/tmp/deamon.pid'), (ARGV[1] || '/tmp/daemon.stdout.log'), (ARGV[2] || '/tmp/daemon.stderr.log')

    # Set up signals for our daemon, for now they just exit the process.
    Signal.trap("HUP") { puts "SIGHUP and exit"; exit }
    Signal.trap("INT") { puts "SIGINT and exit"; exit }
    Signal.trap("QUIT") { puts "SIGQUIT and exit"; exit }
    Signal.trap("HUP") { $stdout.puts "SIGHUP and exit"; exit }
    Signal.trap("INT") { $stdout.puts "SIGINT and exit"; exit }
    Signal.trap("QUIT") { $stdout.puts "SIGQUIT and exit"; exit }

    # Remove this loop and replace with your own daemon logic.
    loop do
  5. mynameisrufus revised this gist Nov 17, 2011. 1 changed file with 8 additions and 7 deletions.
    15 changes: 8 additions & 7 deletions simple_ruby_daemon.rb
    100644 → 100755
    Original file line number Diff line number Diff line change
    @@ -11,13 +11,13 @@
    # 1 second sleep.
    #
    # Most of the code is dedicated to managing a pid file. We want a pid
    # file so we can use a monitoring tool to make sure your daemon keeps
    # file so we can use a monitoring tool to make sure our daemon keeps
    # running.
    #
    # === Why?
    #
    # Writing a daemon sounds hard but as you can see is not that
    # complicated so lets strip away the magic and just write some ruby.
    # complicated, so lets strip away the magic and just write some ruby.
    #
    # === Usage
    #
    @@ -29,7 +29,7 @@
    #
    # $ ./simple_ruby_daemon.rb tmp/simple_ruby_daemon.pid
    #
    # You can check that it is running by running the following:
    # check that it is running by running the following:
    #
    # $ ps aux | grep simple_ruby_daemon
    #
    @@ -58,16 +58,17 @@ def self.write(pid, pidfile)
    # Try and read the existing pid from the pid file and signal the
    # process. Returns true for a non blocking status.
    def self.kill(pid, pidfile)
    Process.kill "HUP", open(pidfile).read.strip.to_i
    opid = open(pidfile).read.strip.to_i
    Process.kill "HUP", opid
    true
    rescue Errno::ENOENT
    $stdout.puts "#{pidfile} did not exist: Errno::ENOENT"
    true
    rescue Errno::ESRCH
    $stdout.puts "Process for the existing PID was not running: Errno::ESRCH"
    $stdout.puts "The process #{opid} did not exist: Errno::ESRCH"
    true
    rescue Errno::EPERM
    $stderr.puts "Lack of privileges to manage #{pidfile}: Errno::EPERM"
    $stderr.puts "Lack of privileges to manage the process #{opid}: Errno::EPERM"
    false
    rescue ::Exception => e
    $stderr.puts "While signaling the PID, unexpected #{e.class}: #{e}"
    @@ -89,4 +90,4 @@ def self.kill(pid, pidfile)
    # Remove this loop and replace with your own daemon logic.
    loop do
    sleep 1
    end
    end
  6. mynameisrufus created this gist Nov 17, 2011.
    92 changes: 92 additions & 0 deletions simple_ruby_daemon.rb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,92 @@
    #!/usr/bin/env ruby
    # == Simple Daemon
    #
    # A simple ruby daemon that you copy and change as needed.
    #
    # === How does it work?
    #
    # All this program does is fork the current process (creates a copy of
    # itself) then exits, the fork (child process) then goes on to run your
    # daemon code. In this example we are just running a while loop with a
    # 1 second sleep.
    #
    # Most of the code is dedicated to managing a pid file. We want a pid
    # file so we can use a monitoring tool to make sure your daemon keeps
    # running.
    #
    # === Why?
    #
    # Writing a daemon sounds hard but as you can see is not that
    # complicated so lets strip away the magic and just write some ruby.
    #
    # === Usage
    #
    # You can run this daemon by running:
    #
    # $ ./simple_ruby_daemon.rb
    #
    # or with an optional pid file location as its first argument:
    #
    # $ ./simple_ruby_daemon.rb tmp/simple_ruby_daemon.pid
    #
    # You can check that it is running by running the following:
    #
    # $ ps aux | grep simple_ruby_daemon
    #
    # Author:: Rufus Post (mailto:rufuspost@gmail.com)
    class SimpleDaemon
    # Checks to see if the current process is the child process and if not
    # will update the pid file with the child pid.
    def self.start(pid, pidfile)
    unless pid.nil?
    raise "Fork failed" if pid == -1
    write(pid, pidfile) if kill(pid, pidfile)
    exit
    end
    end

    # Attempts to write the pid of the forked process to the pid file.
    def self.write(pid, pidfile)
    File.open pidfile, "w" do |f|
    f.write pid
    end
    rescue ::Exception => e
    $stderr.puts "While writing the PID to file, unexpected #{e.class}: #{e}"
    Process.kill "HUP", pid
    end

    # Try and read the existing pid from the pid file and signal the
    # process. Returns true for a non blocking status.
    def self.kill(pid, pidfile)
    Process.kill "HUP", open(pidfile).read.strip.to_i
    true
    rescue Errno::ENOENT
    $stdout.puts "#{pidfile} did not exist: Errno::ENOENT"
    true
    rescue Errno::ESRCH
    $stdout.puts "Process for the existing PID was not running: Errno::ESRCH"
    true
    rescue Errno::EPERM
    $stderr.puts "Lack of privileges to manage #{pidfile}: Errno::EPERM"
    false
    rescue ::Exception => e
    $stderr.puts "While signaling the PID, unexpected #{e.class}: #{e}"
    false
    end
    end

    # Process name of your daemon
    $0 = "simple ruby daemon"

    # Spawn a deamon
    SimpleDaemon.start fork, (ARGV.first || '/tmp/simple_ruby_deamon.pid')

    # Set up signals for our daemon, for now they just exit the process.
    Signal.trap("HUP") { puts "SIGHUP and exit"; exit }
    Signal.trap("INT") { puts "SIGINT and exit"; exit }
    Signal.trap("QUIT") { puts "SIGQUIT and exit"; exit }

    # Remove this loop and replace with your own daemon logic.
    loop do
    sleep 1
    end