Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

Support running thin under daemontools/runit

#40

It would be great to be able to run thin under a service manager such a daemontools/runit/launchd/AIX's SRC. The advantages of such an approach are:
- Unified service control interface. - No use of pidfiles or process table scanning, both of which are brittle (stale pidfiles, pidfile/directory ownerships, issues, process name matching, ps output portability). - Direct notification (SIGCHLD, waitpid()) instead of polling. - Automated process restart capability, a la init.

To make thin play nice with this setup, thin should not background itself and instead wait for any children it forks (and restart them if they die, or alternatively exit so that the service manager can restart the cluster. This is similar to how Apache manages its worker children.

A stripped version of the run method in the swiftiply_mongrel_rails script is shown below to demonstrate the general pattern. In the example the manager doesn't bother to restart any children (hence the call to Process.waitall) but modifying it so that it would restart any dead children so that number_of_children are kept running at all times should not be hard. (One would fix the main loop to start processes while current_processes < wanted_processes and use Process.wait instead of Process.waitall at the bottom so that the loop is reentered after each child dies.)

Sample code:

  def self.run
    args = [ ... ]
    children = []
    number_of_children.times do |i|
      r, w = IO.pipe
      cid = fork
      unless cid # child
        w.close
        Thread.new {
          begin
            r.read # basically blocks until the parent disappears
          ensure
            STDERR.puts "pid #{Process.pid}: parent died... exiting!"
            Kernel.exit
          end
        }
        Mongrel::Runner.new.run(args) # never returns
        exit
      else
        r.close
        children << cid
      end
    end
    $stderr.puts "waiting for children: #{children.join(' ')}"
    Process.waitall
    $stderr.puts "all children exited."
  end

Reported by Jos Backus · February 12th, 2008 @ 04:53 PM

State: open
Milestone: Ruby 1.9
Assigned to: macournoyer macournoyer

Activity

  1. macournoyer
    macournoyer
    • Milestone set to Ruby 1.9
    • State changed from new to open

    I'll try to prototype that this weekend.

    Want concerns me is the extra memory required to run a master process. An empty Ruby VM can use 80 MB on some system.

    But recent fixes in Ruby 1.9 GC improve mem usage w/ fork, see: http://thin.lighthouseapp.com/pr...

    So it might be a good feature for 1.9

    February 13th, 2008 @ 02:26 PM

  2. Jos Backus
    Jos Backus

    Thank you. Let me know if there's anything I can do to help.

    February 13th, 2008 @ 02:40 PM

  3. Geoffrey Grosenbach
    Geoffrey Grosenbach
    • Tag set to cluster, daemon

    In the meantime, see Steve Purcell's rails-runit project, which makes this possible:

    http://github.com/purcell/rails-...

    I'm using it for a few thin apps and it works very well (but requires a bit of setup with runit and a non-root user to run your thin apps).

    November 1st, 2008 @ 04:50 PM

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.