about summary refs log tree commit homepage
path: root/lib/yahns/daemon.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/yahns/daemon.rb')
-rw-r--r--lib/yahns/daemon.rb51
1 files changed, 51 insertions, 0 deletions
diff --git a/lib/yahns/daemon.rb b/lib/yahns/daemon.rb
new file mode 100644
index 0000000..d12ff69
--- /dev/null
+++ b/lib/yahns/daemon.rb
@@ -0,0 +1,51 @@
+# -*- encoding: binary -*-
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+module Yahns::Daemon # :nodoc:
+  # We don't do a lot of standard daemonization stuff:
+  #   * 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.
+  #   * don't bother to chdir("/") here since yahns is designed to
+  #     run inside APP_ROOT.  Yahns will also re-chdir() to
+  #     the directory it was started in when being re-executed
+  #     to pickup code changes if the original deployment directory
+  #     is a symlink or otherwise got replaced.
+  def self.daemon(yahns_server)
+    $stdin.reopen("/dev/null")
+
+    # We only start a new process group if we're not being reexecuted
+    # and inheriting file descriptors from our parent
+    unless ENV['YAHNS_FD']
+      # grandparent - reads pipe, exits when master is ready
+      #  \_ parent  - exits immediately ASAP
+      #      \_ yahns master - writes to pipe when ready
+
+      # We cannot use Yahns::Sigevent (eventfd) here because we need
+      # to detect EOF on unexpected death, not just read/write
+      rd, wr = IO.pipe
+      grandparent = $$
+      if fork
+        wr.close # grandparent does not write
+      else
+        rd.close # yahns master does not read
+        Process.setsid
+        exit if fork # parent dies now
+      end
+
+      if grandparent == $$
+        # this will block until Server#join runs (or it dies)
+        master_pid = (rd.readpartial(16) rescue nil).to_i
+        unless master_pid > 1
+          warn "master failed to start, check stderr log for details"
+          exit!(1)
+        end
+        exit 0
+      else # yahns master process
+        yahns_server.daemon_pipe = wr
+      end
+    end
+    # $stderr/$stderr can/will be redirected separately in the Yahns config
+  end
+end