1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00

Remove TCP mode (#2169)

This commit is contained in:
Nate Berkopec 2020-03-10 09:50:50 -06:00 committed by GitHub
parent fc03781cf3
commit 8d3db816fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 6 additions and 353 deletions

View file

@ -4,12 +4,15 @@
* Add pumactl `thread-backtraces` command to print thread backtraces (#2053)
* Configuration: `environment` is read from `RAILS_ENV`, if `RACK_ENV` can't be found (#2022)
* Do not set user_config to quiet by default to allow for file config (#2074)
* `Puma.stats` now returns a Hash instead of a JSON string (#2086)
* `GC.compact` is called before fork if available (#2093)
* Add `requests_count` to workers stats. (#2106)
* Changed #connected_port to #connected_ports (#2076)
* Deprecations, Removals and Breaking API Changes
* `Puma.stats` now returns a Hash instead of a JSON string (#2086)
* `--control` has been removed. Use `--control-url` (#1487)
* `worker_directory` has been removed. Use `directory`
* `worker_directory` has been removed. Use `directory`.
* `tcp_mode` has been removed without replacement. (#2169)
* Changed #connected_port to #connected_ports (#2076)
* Bugfixes
* Windows update extconf.rb for use with ssp and varied Ruby/MSYS2 combinations (#2069)
@ -24,7 +27,6 @@
* Simplify `Runner#start_control` URL parsing (#2111)
* Removed the IOBuffer extension and replaced with Ruby (#1980)
## 4.3.3 and 3.12.4 / 2020-02-28
* Bugfixes

View file

@ -1,96 +0,0 @@
# TCP mode
Puma also could be used as a TCP server to process incoming TCP
connections.
## Configuration
TCP mode can be enabled with CLI option `--tcp-mode`:
```
$ puma --tcp-mode
```
Default ip and port to listen to are `0.0.0.0` and `9292`. You can configure
them with `--port` and `--bind` options:
```
$ puma --tcp-mode --bind tcp://127.0.0.1:9293
$ puma --tcp-mode --port 9293
```
TCP mode could be set with a configuration file as well with `tcp_mode`
and `tcp_mode!` methods:
```
# config/puma.rb
tcp_mode
```
When Puma starts in the TCP mode it prints the corresponding message:
```
puma --tcp-mode
Puma starting in single mode...
...
* Mode: Lopez Express (tcp)
```
## How to declare an application
An application to process TCP connections should be declared as a
callable object which accepts `env` and `socket` arguments.
`env` argument is a Hash with following structure:
```ruby
{ "thread" => {}, "REMOTE_ADDR" => "127.0.0.1:51133", "log" => "#<Proc:0x000..." }
```
It consists of:
* `thread` - a Hash for each thread in the thread pool that could be
used to store information between requests
* `REMOTE_ADDR` - a client ip address
* `log` - a proc object to write something down
`log` object could be used this way:
```ruby
env['log'].call('message to log')
#> 19/Oct/2019 20:28:53 - 127.0.0.1:51266 - message to log
```
## Example of an application
Let's look at an example of a simple application which just echoes
incoming string:
```ruby
# config/puma.rb
app do |env, socket|
s = socket.gets
socket.puts "Echo #{s}"
end
```
We can easily access the TCP server with `telnet` command and receive an
echo:
```shell
telnet 0.0.0.0 9293
Trying 0.0.0.0...
Connected to 0.0.0.0.
Escape character is '^]'.
sssss
Echo sssss
^CConnection closed by foreign host.
```
## Socket management
After the application finishes, Puma closes the socket. In order to
prevent this, the application should set `env['detach'] = true`.

View file

@ -187,10 +187,6 @@ module Puma
end
end
o.on "--tcp-mode", "Run the app in raw TCP mode instead of HTTP mode" do
user_config.tcp_mode!
end
o.on "--early-hints", "Enable early hints support" do
user_config.early_hints
end

View file

@ -245,14 +245,6 @@ module Puma
def app
found = options[:app] || load_rackup
if @options[:mode] == :tcp
require 'puma/tcp_logger'
logger = @options[:logger]
quiet = !@options[:log_requests]
return TCPLogger.new(logger, found, quiet)
end
if @options[:log_requests]
require 'puma/commonlogger'
logger = @options[:logger]

View file

@ -325,12 +325,6 @@ module Puma
@options[:rackup] = path.to_s
end
# Run Puma in TCP mode
#
def tcp_mode!
@options[:mode] = :tcp
end
def early_hints(answer=true)
@options[:early_hints] = answer
end
@ -536,11 +530,6 @@ module Puma
@options[:directory] = dir.to_s
end
# Run the app as a raw TCP app instead of an HTTP rack app.
def tcp_mode
@options[:mode] = :tcp
end
# Preload the application before starting the workers; this conflicts with
# phased restart feature. This is off by default.
#

View file

@ -92,10 +92,6 @@ module Puma
log "* Version #{Puma::Const::PUMA_VERSION} (#{ruby_engine}), codename: #{Puma::Const::CODE_NAME}"
log "* Min threads: #{min_t}, max threads: #{max_t}"
log "* Environment: #{ENV['RACK_ENV']}"
if @options[:mode] == :tcp
log "* Mode: Lopez Express (tcp)"
end
end
def redirected_io?
@ -158,10 +154,6 @@ module Puma
server.max_threads = max_t
server.inherit_binder @launcher.binder
if @options[:mode] == :tcp
server.tcp_mode!
end
if @options[:early_hints]
server.early_hints = true
end

View file

@ -99,10 +99,6 @@ module Puma
@binder = bind
end
def tcp_mode!
@mode = :tcp
end
# On Linux, use TCP_CORK to better control how the TCP stack
# packetizes our stream. This improves both latency and throughput.
#
@ -176,107 +172,6 @@ module Puma
@thread_pool and @thread_pool.pool_capacity
end
# Lopez Mode == raw tcp apps
def run_lopez_mode(background=true)
@thread_pool = ThreadPool.new(@min_threads,
@max_threads,
Hash) do |client, tl|
io = client.to_io
addr = io.peeraddr.last
if addr.empty?
# Set unix socket addrs to localhost
addr = "127.0.0.1:0"
else
addr = "#{addr}:#{io.peeraddr[1]}"
end
env = { 'thread' => tl, REMOTE_ADDR => addr }
begin
@app.call env, client.to_io
rescue Object => e
STDERR.puts "! Detected exception at toplevel: #{e.message} (#{e.class})"
STDERR.puts e.backtrace
end
client.close unless env['detach']
end
@events.fire :state, :running
if background
@thread = Thread.new do
Puma.set_thread_name "server"
handle_servers_lopez_mode
end
return @thread
else
handle_servers_lopez_mode
end
end
def handle_servers_lopez_mode
begin
check = @check
sockets = [check] + @binder.ios
pool = @thread_pool
while @status == :run
begin
ios = IO.select sockets
ios.first.each do |sock|
if sock == check
break if handle_check
else
begin
if io = sock.accept_nonblock
client = Client.new io, nil
pool << client
end
rescue SystemCallError
# nothing
rescue Errno::ECONNABORTED
# client closed the socket even before accept
begin
io.close
rescue
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
end
end
end
rescue Object => e
@events.unknown_error self, e, "Listen loop"
end
end
@events.fire :state, @status
graceful_shutdown if @status == :stop || @status == :restart
rescue Exception => e
STDERR.puts "Exception handling servers: #{e.message} (#{e.class})"
STDERR.puts e.backtrace
ensure
begin
@check.close
rescue
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
end
# Prevent can't modify frozen IOError (RuntimeError)
begin
@notify.close
rescue IOError
# no biggy
end
end
@events.fire :state, :done
end
# Runs the server.
#
# If +background+ is true (the default) then a thread is spun
@ -290,10 +185,6 @@ module Puma
@status = :run
if @mode == :tcp
return run_lopez_mode(background)
end
queue_requests = @queue_requests
@thread_pool = ThreadPool.new(@min_threads,

View file

@ -1,41 +0,0 @@
# frozen_string_literal: true
module Puma
class TCPLogger
def initialize(logger, app, quiet=false)
@logger = logger
@app = app
@quiet = quiet
end
FORMAT = "%s - %s"
def log(who, str)
now = Time.now.strftime("%d/%b/%Y %H:%M:%S")
log_str = "#{now} - #{who} - #{str}"
case @logger
when IO
@logger.puts log_str
when Events
@logger.log log_str
end
end
def call(env, socket)
who = env[Const::REMOTE_ADDR]
log who, "connected" unless @quiet
env['log'] = lambda { |str| log(who, str) }
begin
@app.call env, socket
rescue Object => e
log who, "exception: #{e.message} (#{e.class})"
else
log who, "disconnected" unless @quiet
end
end
end
end

View file

@ -1,38 +0,0 @@
require_relative "helper"
require "puma/tcp_logger"
class TestTCPLogger < Minitest::Test
def setup
@events = Puma::Events.new STDOUT, STDERR
@server = Puma::Server.new nil, @events
@server.app = proc { |env, socket|}
@server.tcp_mode!
@socket = nil
end
def test_events
# in lib/puma/launcher.rb:85
# Puma::Events is default tcp_logger for cluster mode
logger = Puma::Events.new(STDOUT, STDERR)
out, err = capture_subprocess_io do
Puma::TCPLogger.new(logger, @server.app).call({}, @socket)
end
assert_match(/connected/, out)
assert_equal('', err)
end
def test_io
# in lib/puma/configuration.rb:184
# STDOUT is default tcp_logger for single mode
logger = STDOUT
out, err = capture_subprocess_io do
Puma::TCPLogger.new(logger, @server.app).call({}, @socket)
end
assert_match(/connected/, out)
assert_equal('', err)
end
end

View file

@ -1,34 +0,0 @@
require_relative "helper"
class TestTCPRack < Minitest::Test
def setup
@port = UniquePort.call
@host = "127.0.0.1"
@events = Puma::Events.new STDOUT, STDERR
@server = Puma::Server.new nil, @events
end
def teardown
@server.stop(true)
end
def test_passes_the_socket
@server.tcp_mode!
body = "We sell hats for a discount!\n"
@server.app = proc do |env, socket|
socket << body
socket.close
end
@server.add_tcp_listener @host, @port
@server.run
sock = TCPSocket.new @host, @port
assert_equal body, sock.read
end
end