From d973de0d6dfdf799e111d9f9a71170b61a0ac100 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 19 Oct 2013 22:14:59 +0000 Subject: SIGUSR2 handling uses Process.spawn + tests We no longer have to worry about 1.8 compatibility, so use Process.spawn and shorten our code. Also, add tests for this functionality. --- lib/yahns/server.rb | 21 ++++++-------- test/test_bin.rb | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb index e8f1213..e664293 100644 --- a/lib/yahns/server.rb +++ b/lib/yahns/server.rb @@ -173,19 +173,14 @@ class Yahns::Server # :nodoc: end end - @reexec_pid = fork do - redirects = {} - listeners.each do |sock| - sock.close_on_exec = false - redirects[sock.fileno] = sock - end - ENV['YAHNS_FD'] = redirects.keys.map(&:to_s).join(',') - Dir.chdir(@config.value(:working_directory) || Yahns::START[:cwd]) - cmd = [ Yahns::START[0] ].concat(Yahns::START[:argv]) - @logger.info "executing #{cmd.inspect} (in #{Dir.pwd})" - cmd << redirects - exec(*cmd) - end + opts = {} + @listeners.each { |sock| opts[sock.fileno] = sock } + env = { "YAHNS_FD" => opts.keys.map(&:to_s).join(',') } + opts[:chdir] = @config.value(:working_directory) || Yahns::START[:cwd] + cmd = [ Yahns::START[0] ].concat(Yahns::START[:argv]) + @logger.info "spawning #{cmd.inspect} (in #{opts[:chdir]})" + cmd << opts + @reexec_pid = Process.spawn(env, *cmd) proc_name 'master (old)' end diff --git a/test/test_bin.rb b/test/test_bin.rb index aab4616..d21e8b9 100644 --- a/test/test_bin.rb +++ b/test/test_bin.rb @@ -94,4 +94,83 @@ class TestBin < Testcase end @pid.close! if @pid end + + def test_usr2_preload_noworker; usr2(true, false); end + def test_usr2_preload_worker; usr2(true, true); end + def test_usr2_nopreload_worker; usr2(false, true); end + def test_usr2_nopreload_noworker; usr2(false, false); end + + def usr2(preload, worker) + Dir.mktmpdir { |tmpdir| usr2_dir(tmpdir, preload, worker) } + end + + def usr2_dir(tmpdir, preload, worker) + exe = "#{tmpdir}/yahns" + + # need to fork here since tests are MT and the FD can leak out and go to + # other processes which fork (but do not exec), causing ETXTBUSY on + # Process.spawn + pid = fork do + ruby = "#!#{`which ruby`}" + File.open(exe, "w") { |y| + lines = File.readlines("bin/yahns") + lines[0] = ruby + y.chmod(0755) + y.syswrite(lines.join) + } + end + _, status = Process.waitpid2(pid) + assert status.success?, status.inspect + + @pid = tmpfile(%w(test_bin_daemon .pid)) + host, port = @srv.addr[3], @srv.addr[1] + @ru = tmpfile(%w(test_bin_daemon .ru)) + @ru.puts("use Rack::ContentLength") + @ru.puts("use Rack::ContentType, 'text/plain'") + @ru.puts("run lambda { |_| [ 200, {}, [ Process.pid.to_s ] ] }") + cfg = tmpfile(%w(test_bin_daemon_conf .rb)) + cfg.puts "pid '#{@pid.path}'" + cfg.puts "stderr_path '#{@err.path}'" + cfg.puts "worker_processes 1" if worker + cfg.puts "app(:rack, '#{@ru.path}', preload: #{preload}) do" + cfg.puts " listen '#{host}:#{port}'" + cfg.puts "end" + env = { + "YAHNS_FD" => @srv.fileno.to_s, + "PATH" => "#{tmpdir}:#{ENV['PATH']}", + "RUBYLIB" => "#{Dir.pwd}/lib", + } + cmd = %W(#{exe} -D -c #{cfg.path}) + cmd << { @srv => @srv, close_others: true } + pid = GTL.synchronize { Process.spawn(env, *cmd) } + res = Net::HTTP.start(host, port) { |h| h.get("/") } + assert_equal 200, res.code.to_i + orig = res.body + Process.kill(:USR2, pid) + Timeout.timeout(10) do + begin + sleep 0.01 + newpid = File.read(@pid.path) + rescue Errno::ENOENT + end until newpid.to_i != pid + end + Process.kill(:QUIT, pid) + _, status = Timeout.timeout(10) { Process.waitpid2(pid) } + assert status.success?, status + res = Net::HTTP.start(host, port) { |h| h.get("/") } + assert_equal 200, res.code.to_i + refute_equal orig, res.body + rescue => e + Yahns::Log.exception(Logger.new($stderr), "test", e) + raise + ensure + File.unlink(exe) if exe + cfg.close! if cfg + pid = File.read(@pid.path) + pid = pid.to_i + assert_operator pid, :>, 0 + Process.kill(:QUIT, pid) + poke_until_dead pid + @pid.close! + end end -- cgit v1.2.3-24-ge0c7