yahns Ruby server user/dev discussion
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: yahns-public@yhbt.net
Subject: [PATCH] emulate sd_listen_fds for systemd support
Date: Wed, 15 Jul 2015 08:20:59 +0000	[thread overview]
Message-ID: <1436948459-9954-1-git-send-email-e@80x24.org> (raw)

systemd socket emulation shares FDs across execve, just like
the built-in SIGUSR2 upgrade process in unicorn.  Thus it is
easy to support inheriting sockets from systemd.
---
 lib/yahns/server.rb | 16 +++++++++++++---
 test/test_bin.rb    | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb
index b6663e1..01334ca 100644
--- a/lib/yahns/server.rb
+++ b/lib/yahns/server.rb
@@ -312,12 +312,22 @@ class Yahns::Server # :nodoc:
     # because that can completely break the non-blocking one.
     # Unfortunately, there is no one-off MSG_DONTWAIT-like flag for
     # accept4(2).
-    inherited = ENV['YAHNS_FD'].to_s.split(',').map! do |fd|
-      io = Socket.for_fd(fd.to_i)
+    inherited = ENV['YAHNS_FD'].to_s.split(',')
+
+    # emulate sd_listen_fds() for systemd
+    sd_pid, sd_fds = ENV.values_at('LISTEN_PID', 'LISTEN_FDS')
+    if sd_pid && sd_pid.to_i == $$
+      # 3 = SD_LISTEN_FDS_START
+      inherited.concat((3...(3 + sd_fds.to_i)).map { |fd| Socket.for_fd(fd) })
+    end
+    # to ease debugging, we will not unset LISTEN_PID and LISTEN_FDS
+
+    inherited.map! do |fd|
+      io = String === fd ? Socket.for_fd(fd.to_i) : fd
       opts = sock_opts(io)
       io = server_cast(io, opts)
       set_server_sockopt(io, opts)
-      @logger.info "inherited addr=#{sock_name(io)} fd=#{fd}"
+      @logger.info "inherited addr=#{sock_name(io)} fd=#{io.fileno}"
       io
     end
 
diff --git a/test/test_bin.rb b/test/test_bin.rb
index 8944eb3..b778a0d 100644
--- a/test/test_bin.rb
+++ b/test/test_bin.rb
@@ -11,6 +11,40 @@ class TestBin < Testcase
     @cmd = %W(ruby -I lib bin/yahns)
   end
 
+  def test_listen_fd3
+    return unless RUBY_VERSION.to_f > 2.3 # Fixed in ruby/trunk r51209, actually
+    @srv.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, 0)
+    host, port = @srv.addr[3], @srv.addr[1]
+
+    ru = tmpfile(%w(test_bin_daemon .ru))
+    ru.write("require 'rack/lobster'; run Rack::Lobster.new\n")
+    cmd = %W(ruby -I lib bin/yahns-rackup
+             -E none -p #{port} -o #{host} #{ru.path})
+    pid = fork do # emulate a systemd environment
+      env = {
+        'LISTEN_PID' => $$.to_s,
+        'LISTEN_FDS' => '1',
+      }
+      exec env, *cmd, 3 => @srv, err: @err.path
+    end
+    Net::HTTP.start(host, port) do |http|
+      req = Net::HTTP::Get.new("/")
+      res = http.request(req)
+      assert_equal 200, res.code.to_i
+      assert_equal "keep-alive", res["Connection"]
+    end
+
+    assert_equal 1, @srv.getsockopt(:SOL_SOCKET, :SO_KEEPALIVE).int,
+                 'ensure the inheriting process applies TCP socket options'
+  ensure
+    if pid
+      Process.kill(:QUIT, pid)
+      _, status = Process.waitpid2(pid)
+      assert status.success?, status.inspect
+    end
+    ru.close! if ru
+  end
+
   def test_bin_daemon_noworker_inherit
     bin_daemon(false, true)
   end
-- 
EW


                 reply	other threads:[~2015-07-15  8:20 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://yhbt.net/yahns/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1436948459-9954-1-git-send-email-e@80x24.org \
    --to=e@80x24.org \
    --cc=yahns-public@yhbt.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhbt.net/yahns.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).