Allow backlog parameter to be set with ssl_bind DSL (#2780)

Hint about backlog upper limit due to net.core.somaxconn
Guard against invalid backlog value
This commit is contained in:
Dalibor Nasevic 2022-01-01 23:11:22 +01:00 committed by GitHub
parent 2b6968f9d4
commit 4ac14482f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 10 deletions

View File

@ -31,10 +31,10 @@ _workers_, and we sometimes call the threads created by Puma's
![https://bit.ly/2zwzhEK](images/puma-connection-flow.png)
* Upon startup, Puma listens on a TCP or UNIX socket.
* The backlog of this socket is configured (with a default of 1024). The
backlog determines the size of the queue for unaccepted connections.
Generally, you'll never hit the backlog cap in production. If the backlog is
full, the operating system refuses new connections.
* The backlog of this socket is configured with a default of 1024, but the
actual backlog value is capped by the `net.core.somaxconn` sysctl value.
The backlog determines the size of the queue for unaccepted connections. If
the backlog is full, the operating system is not accepting new connections.
* This socket backlog is distinct from the `backlog` of work as reported by
`Puma.stats` or the control server. The backlog that `Puma.stats` refers to
represents the number of connections in the process' `todo` set waiting for

View File

@ -168,9 +168,9 @@ module Puma
params = Util.parse_query uri.query
opt = params.key?('low_latency') && params['low_latency'] != 'false'
bak = params.fetch('backlog', 1024).to_i
backlog = params.fetch('backlog', 1024).to_i
io = add_tcp_listener uri.host, uri.port, opt, bak
io = add_tcp_listener uri.host, uri.port, opt, backlog
@ios[ios_len..-1].each do |i|
addr = loc_addr_str i
@ -255,7 +255,8 @@ module Puma
logger.log "* Activated #{str}"
else
ios_len = @ios.length
io = add_ssl_listener uri.host, uri.port, ctx
backlog = params.fetch('backlog', 1024).to_i
io = add_ssl_listener uri.host, uri.port, ctx, optimize_for_latency = true, backlog
@ios[ios_len..-1].each do |i|
addr = loc_addr_str i

View File

@ -48,6 +48,8 @@ module Puma
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
backlog_str = opts[:backlog] ? "&backlog=#{Integer(opts[:backlog])}" : ''
if defined?(JRUBY_VERSION)
ssl_cipher_list = opts[:ssl_cipher_list] ?
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
@ -55,7 +57,7 @@ module Puma
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
"&verify_mode=#{verify}#{tls_str}#{ca_additions}#{backlog_str}"
else
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
@ -64,7 +66,7 @@ module Puma
"&verification_flags=#{Array(ary).join ','}" : nil
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}"
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}#{backlog_str}"
end
end

View File

@ -275,6 +275,24 @@ class TestBinder < TestBinderBase
assert_equal @events.stderr, env_hash["rack.errors"]
end
def test_ssl_binder_sets_backlog
skip_unless :ssl
host = '127.0.0.1'
port = UniquePort.call
tcp_server = TCPServer.new(host, port)
tcp_server.define_singleton_method(:listen) do |backlog|
Thread.current[:backlog] = backlog
super(backlog)
end
TCPServer.stub(:new, tcp_server) do
@binder.parse ["ssl://#{host}:#{port}?#{ssl_query}&backlog=2048"], @events
end
assert_equal 2048, Thread.current[:backlog]
end
def test_close_calls_close_on_ios
@mocked_ios = [Minitest::Mock.new, Minitest::Mock.new]
@mocked_ios.each { |m| m.expect(:close, true) }

View File

@ -98,6 +98,21 @@ class TestConfigFile < TestConfigFileBase
assert_equal [ssl_binding], conf.options[:binds]
end
def test_ssl_bind_with_backlog
skip_unless :ssl
conf = Puma::Configuration.new do |c|
c.ssl_bind "0.0.0.0", "9292", {
backlog: "2048",
}
end
conf.load
ssl_binding = conf.options[:binds].first
assert ssl_binding.include?('&backlog=2048')
end
def test_ssl_bind_jruby
skip_unless :jruby
skip_unless :ssl

View File

@ -5,7 +5,7 @@ require "puma/thread_pool"
class TestThreadPool < Minitest::Test
def teardown
@pool.shutdown(1) if @pool
@pool.shutdown(1) if defined?(@pool)
end
def new_pool(min, max, &block)