* [ANN] yahns 1.6.0 -_- sleepy app server for Ruby
@ 2015-03-09 9:49 4% Eric Wong
0 siblings, 0 replies; 3+ results
From: Eric Wong @ 2015-03-09 9:49 UTC (permalink / raw)
To: ruby-talk, yahns-public
A Free Software, multi-threaded, non-blocking network application server
designed for low _idle_ power consumption. It is primarily optimized
for applications with occasional users which see little or no traffic.
yahns currently hosts Rack/HTTP applications, but may eventually support
other application types. Unlike some existing servers, yahns is
extremely sensitive to fatal bugs in the applications it hosts.
Changes: reduced allocations and bugfixes
This release fixes a bug where previously-configured-but-now-removed
listeners were inherited across USR2 upgrades are not shutdown
immediately in the child.
There are also minor reductions in allocations which can save a few
hundred bytes statically and also whenever write buffering is necessary
for large responses.
Some minor documentation updates improvements in extras, too.
shortlog of changes since 1.5.0:
README: add link to mailing list archives
test_ssl: factor out server SSLContext creation
doc: add design_notes document
reduce File::Stat object allocations
update comments about wbuf_close return values
wbuf: lazily (re)create temporary file
fix compatibility with unicorn.git
skip tests requiring String#b on 1.9.3
use the monotonic clock under Ruby 2.1+
favor Class.new for method-less classes
extras/proxy_pass: save memory in String#split arg
extras/proxy_pass: do not name unused variable
extras/proxy_pass: log exceptions leading to 502
extras/proxy_pass: flesh out upload support + tests
acceptor: close inherited-but-unneeded sockets
See the git repository for more: git clone git://yhbt.net/yahns
Please note the disclaimer:
yahns is extremely sensitive to fatal bugs in the apps it hosts. There
is no (and never will be) any built-in "watchdog"-type feature to kill
stuck processes/threads. Each yahns process may be handling thousands
of clients; unexpectedly killing the process will abort _all_ of those
connections. Lives may be lost!
yahns hackers are not responsible for your application/library bugs.
Use an application server which is tolerant of buggy applications
if you cannot be bothered to fix all your fatal bugs.
* git clone git://yhbt.net/yahns
* http://yahns.yhbt.net/README
* http://yahns.yhbt.net/NEWS.atom.xml
* we like plain-text email yahns-public@yhbt.net
* and archive all the mail we receive: http://yhbt.net/yahns-public/
lrg nabgure ubeevoyl-anzrq freire
lrf, lnuaf vf frys-ubfgvat vgf bja fvgrf fvapr yngr 2013
^ permalink raw reply [relevance 4%]
* [PATCH] acceptor: close inherited-but-unneeded sockets
@ 2015-03-09 4:46 4% Eric Wong
0 siblings, 0 replies; 3+ results
From: Eric Wong @ 2015-03-09 4:46 UTC (permalink / raw)
To: yahns-public
When inheriting sockets from the parent via YAHNS_FD, we must close
sockets ASAP if they are unconfigured in the child. This bug exists
in yahns (and not unicorn) because of the trickier shutdown routine
we do for blocking accept system calls to work reliably with the
threading support in mainline Ruby 2.x. This bug would not exist
in a purely C server using blocking accept, either.
---
I'll probably release 1.6.0 in a few hours with this and what's been
sitting in master since the last release. If there's more risk-averse
users, maybe a 1.5.1 with just this patch is warranted, but I doubt
it (abguvat nobhg lnuaf vf sbe gur evfx-nirefr pebjq :P).
Eric Wong (15):
README: add link to mailing list archives
test_ssl: factor out server SSLContext creation
doc: add design_notes document
reduce File::Stat object allocations
update comments about wbuf_close return values
wbuf: lazily (re)create temporary file
fix compatibility with unicorn.git
skip tests requiring String#b on 1.9.3
use the monotonic clock under Ruby 2.1+
favor Class.new for method-less classes
extras/proxy_pass: save memory in String#split arg
extras/proxy_pass: do not name unused variable
extras/proxy_pass: log exceptions leading to 502
extras/proxy_pass: flesh out upload support + tests
acceptor: close inherited-but-unneeded sockets
lib/yahns/acceptor.rb | 5 ++++-
test/test_server.rb | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/lib/yahns/acceptor.rb b/lib/yahns/acceptor.rb
index cd9e055..0cebea2 100644
--- a/lib/yahns/acceptor.rb
+++ b/lib/yahns/acceptor.rb
@@ -19,7 +19,10 @@ module Yahns::Acceptor # :nodoc:
# just keep looping this on every acceptor until the associated thread dies
def ac_quit
- return true unless defined?(@thrs)
+ unless defined?(@thrs) # acceptor has not started yet, freshly inherited
+ close
+ return true
+ end
@thrs.each { |t| t[:yahns_quit] = true }
return true if __ac_quit_done?
diff --git a/test/test_server.rb b/test/test_server.rb
index 69babb3..b7cb3e6 100644
--- a/test/test_server.rb
+++ b/test/test_server.rb
@@ -804,4 +804,43 @@ class TestServer < Testcase
ensure
quit_wait(pid)
end
+
+ def test_inherit_too_many
+ err = @err
+ s2 = TCPServer.new(ENV["TEST_HOST"] || "127.0.0.1", 0)
+ cfg = Yahns::Config.new
+ host, port = @srv.addr[3], @srv.addr[1]
+ cfg.instance_eval do
+ ru = lambda { |_| [ 200, {'Content-Length'=>'2'}, ['HI'] ] }
+ GTL.synchronize { app(:rack, ru) { listen "#{host}:#{port}" } }
+ logger(Logger.new(err.path))
+ end
+ mkserver(cfg, @srv) do
+ s2.autoclose = false
+ ENV["YAHNS_FD"] = "#{@srv.fileno},#{s2.fileno}"
+ end
+ run_client(host, port) { |res| assert_equal "HI", res.body }
+ th = Thread.new do
+ c = s2.accept
+ c.readpartial(1234)
+ c.write "HTTP/1.0 666 OK\r\n\r\nGO AWAY"
+ c.close
+ :OK
+ end
+ Thread.pass
+ s2host, s2port = s2.addr[3], s2.addr[1]
+ Net::HTTP.start(s2host, s2port) do |http|
+ res = http.request(Net::HTTP::Get.new("/"))
+ assert_equal 666, res.code.to_i
+ assert_equal "GO AWAY", res.body
+ end
+ assert_equal :OK, th.value
+ tmpc = TCPSocket.new(s2host, s2port)
+ a2 = s2.accept
+ assert_nil IO.select([a2], nil, nil, 0.05)
+ tmpc.close
+ assert_nil a2.read(1)
+ a2.close
+ s2.close
+ end
end
--
EW
^ permalink raw reply related [relevance 4%]
* [PATCH] use the monotonic clock under Ruby 2.1+
@ 2015-02-05 20:47 7% Eric Wong
0 siblings, 0 replies; 3+ results
From: Eric Wong @ 2015-02-05 20:47 UTC (permalink / raw)
To: yahns-public; +Cc: Eric Wong
The monotonic clock is immune to time adjustments so it is not
thrown off by misconfigured clocks. Process.clock_gettime also
generates less garbage on 64-bit systems due to the use of Flonum.
---
lib/yahns.rb | 13 +++++++++++++
lib/yahns/client_expire_generic.rb | 2 +-
lib/yahns/fdmap.rb | 4 ++--
lib/yahns/server.rb | 6 +++---
4 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/lib/yahns.rb b/lib/yahns.rb
index a55837f..fd84223 100644
--- a/lib/yahns.rb
+++ b/lib/yahns.rb
@@ -55,6 +55,19 @@ module Yahns # :nodoc:
class ClientTimeout < RuntimeError # :nodoc:
end
+
+ # try to use the monotonic clock in Ruby >= 2.1, it is immune to clock
+ # offset adjustments and generates less garbage (Float vs Time object)
+ begin
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ def self.now
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ end
+ rescue NameError, NoMethodError
+ def self.now # Ruby <= 2.0
+ Time.now.to_f
+ end
+ end
end
# FIXME: require lazily
diff --git a/lib/yahns/client_expire_generic.rb b/lib/yahns/client_expire_generic.rb
index 7e80406..2beabb8 100644
--- a/lib/yahns/client_expire_generic.rb
+++ b/lib/yahns/client_expire_generic.rb
@@ -2,7 +2,7 @@
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
module Yahns::ClientExpireGeneric # :nodoc:
def __timestamp
- Time.now.to_f
+ Yahns.now
end
def yahns_init
diff --git a/lib/yahns/fdmap.rb b/lib/yahns/fdmap.rb
index bac327e..d1f752a 100644
--- a/lib/yahns/fdmap.rb
+++ b/lib/yahns/fdmap.rb
@@ -81,7 +81,7 @@ class Yahns::Fdmap # :nodoc:
def __expire(timeout)
return if @count == 0
nr = 0
- now = Time.now.to_f
+ now = Yahns.now
(now - @last_expire) >= 1.0 or return # don't expire too frequently
# @fdmap_ary may be huge, so always expire a bunch at once to
@@ -93,7 +93,7 @@ class Yahns::Fdmap # :nodoc:
nr += c.yahns_expire(tout)
end
- @last_expire = Time.now.to_f
+ @last_expire = Yahns.now
msg = timeout ? "timeout=#{timeout}" : "client_timeout"
@logger.info("dropping #{nr} of #@count clients for #{msg}")
end
diff --git a/lib/yahns/server.rb b/lib/yahns/server.rb
index e05a0e4..3b9addc 100644
--- a/lib/yahns/server.rb
+++ b/lib/yahns/server.rb
@@ -385,7 +385,7 @@ class Yahns::Server # :nodoc:
def quit_enter(alive)
if alive
@logger.info("gracefully exiting shutdown_timeout=#@shutdown_timeout")
- @shutdown_expire ||= Time.now + @shutdown_timeout + 1
+ @shutdown_expire ||= Yahns.now + @shutdown_timeout + 1
else # drop connections immediately if signaled twice
@logger.info("graceful exit aborted, exiting immediately")
# we will still call any app-defined at_exit hooks here
@@ -416,7 +416,7 @@ class Yahns::Server # :nodoc:
# response bodies out (e.g. "tail -F") Oh well, have a timeout
begin
@wthr.delete_if { |t| t.join(0.01) }
- end while @wthr[0] && Time.now <= @shutdown_expire
+ end while @wthr[0] && Yahns.now <= @shutdown_expire
# cleanup, our job is done
@queues.each(&:close).clear
@@ -466,7 +466,7 @@ class Yahns::Server # :nodoc:
def dropping(fdmap)
if drop_acceptors[0] || fdmap.size > 0
- timeout = @shutdown_expire < Time.now ? -1 : @shutdown_timeout
+ timeout = @shutdown_expire < Yahns.now ? -1 : @shutdown_timeout
fdmap.desperate_expire(timeout)
true
else
--
EW
^ permalink raw reply related [relevance 7%]
Results 1-3 of 3 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2015-02-05 20:47 7% [PATCH] use the monotonic clock under Ruby 2.1+ Eric Wong
2015-03-09 4:46 4% [PATCH] acceptor: close inherited-but-unneeded sockets Eric Wong
2015-03-09 9:49 4% [ANN] yahns 1.6.0 -_- sleepy app server for Ruby Eric Wong
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).