3

tl;dr: rackup -p 1234 <= works. rackup -p 1234 -D <= creates zombies. Why?

I'm running a Grape API server with supporting functions in a separate file. My aim is for the start of the server to create a long-running separate background process defined in the supporting functions that pings a database at an interval and performs some actions if data with certain flags are found. This works perfectly until the server is racked-up as a daemon. When racked-up as a daemon, each call to the server creates a zombie process.

Why? I've read what I can on zombies, forking, etc. but must be missing some key concept ...

Rack configuration (config.ru)

require './server.rb'

run Application::API

Grape server (server.rb)

require_relative 'support.rb'
module Application
  class API < Grape::API
    helpers do
      def current_runner
        @current_runner ||= Run.new
      end
      # ...
    end
    resource :tests do
      post :create do
        current_runner # <= Edit: forgot to copy this over 
        @current_runner.create
      end
      get :lookup do
        current_runner # <= Edit: forgot to copy this over 
        @current_runner.lookup
      end
      # ...
    end
  end
end

Supporting functions (support.rb)

class Run
  def initialize
    # ...   
    test_untested
  end
  # ... other non-forked functions including 'lookup' and 'create'
  def test_untested
    # Text file with process ID to protect from duplicate listeners
    pid = ""
    File.open("processid.txt", "r") do |f|
      f.each_line do |line|
        pid << line
      end
    end
    pid = pid.to_s.gsub(/[^0-9]/, "").to_i
    # If the process responds to kill signal 0
    # a listener is still alive, and we need to exit
    pid_active = nil
    unless pid < 100
      begin
        pid_active = true if ((Process.kill 0, pid) > 0)
      rescue Errno::ESRCH => e
        pid_active = false
      end
    end
    unless pid_active
      Process.fork do # Tried Process.daemon -- it never runs.
        Process.detach(Process.pid) # <= Also tried 'Process.setsid' instead ...
        # Application logic ...
      end
    end
  end
end
r = Run.new

Edit: FYI: I'm on a 2-core 32-bit CentOS 6.5 server.

Sam
  • 1,205
  • 1
  • 21
  • 39

1 Answers1

0

Does it help to remove

r = Run.new 

at the bottom of support.rb

When you require 'support.rb' The process that is running server.rb will automatically spawn a new process where it will run the Run class by executing the line at the bottom of the file.

Henry Chinner
  • 429
  • 3
  • 9
  • You're right to think that removing that line will not create zombies. But it accomplishes that by not executing the application logic (in an intentional infinite loop), and so defeats the purpose. Sorry if that wasn't clear. – Sam Dec 11 '14 at 09:57