当 运行 Sinatra 在已占用的端口上时避免显示回溯

Avoid display of backtrace when running Sinatra on an already taken port

当 Sinatra 无法正确 运行 服务器(例如,由于端口已被使用)时,阻止 Sinatra 显示完整回溯的正确方法是什么?

这是一个示例 sinatra 应用程序:

# test.rb
require 'sinatra'
require 'bundler/inline'

gemfile do
  gem 'sinatra'
  gem 'puma'
end

set :bind, "0.0.0.0"
set :port, 3000

get '/' do
  "hello"
end

然后运行与ruby test.rb连接一次,占用端口

然后,运行在另一个终端中再次使用它 window,并显示完整的错误回溯:

$ ruby test.rb
== Sinatra (v2.0.4) has taken the stage on 3000 for development with backup from Puma
Puma starting in single mode...
* Version 3.12.0 (ruby 2.5.0-p0), codename: Llamas in Pajamas
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000
== Someone is already performing on port 3000!
Traceback (most recent call last):
        5: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/main.rb:26:in `block in <module:Sinatra>'
        4: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1464:in `run!'
        3: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1464:in `ensure in run!'
        2: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1439:in `quit!'
        1: from /store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/launcher.rb:147:in `stop'
/store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/single.rb:27:in `stop': undefined method `stop' for nil:NilClass (NoMethodError)
Traceback (most recent call last):
        3: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1545:in `block in setup_traps'
        2: from /store/gems/ruby-2.5.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1439:in `quit!'
        1: from /store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/launcher.rb:147:in `stop'
/store/gems/ruby-2.5.0/gems/puma-3.12.0/lib/puma/single.rb:27:in `stop': undefined method `stop' for nil:NilClass (NoMethodError)

因为我将它用作嵌入式服务器,所以我希望输出简单并且带有 Sinatra 已经显示的友好错误:

== Someone is already performing on port 3000!

并避免显示回溯。

Ruby 默认输出错误信息到 STDOUT。但是如果你在 *nix 系统上,你可以这样做:

ruby test.rb > /dev/null 2>&1

对于windows你大概可以做到

ruby test.rb > NULL

windows powershell

ruby test.rb > $null

但对于 windows 另见 Is there a /dev/null on Windows?

但是如果你想在服务器为 运行 时以编程方式抑制输出,这应该适用于 *nix 但不确定 windows

# test.rb
require 'sinatra'
require 'bundler/inline'

gemfile do
  gem 'sinatra'
  gem 'puma'
end

set :bind, "0.0.0.0"
set :port, 3000

get '/' do
  "hello"
end

unless `ps aux | grep sinatra`.match('tcp://0.0.0.0:3000')
  STDOUT.reopen('/dev/null', 'w')
  STDERR.reopen('/dev/null', 'w')
end

suppresing output to console with ruby

您可以通过在允许 Sinatra 和 Puma 接管之前尝试侦听端口来测试端口是否正在使用。这不是 100% 有效,因为存在竞争条件,您可以打开和关闭端口,但在 Sinatra/Puma 完成初始化之前,一些其他进程出现并侦听同一端口,但它应该适合您使用 -案例(这似乎只是一个装饰黑客)。

test.rb 中的任意位置插入此代码:

require 'socket'
include Socket::Constants

begin
  # Open and close the port
  socket = Socket.new(AF_INET, SOCK_STREAM, 0)
  sockaddr = Socket.pack_sockaddr_in(3000, '0.0.0.0')
  socket.bind(sockaddr)
  socket.listen(1)
  socket.close
rescue Errno::EADDRINUSE => error
  # Traps the same error that is trapped by Sinatra and exits if raised
  puts error.message
  exit
end

第一个开始 ruby test.rb:

== Sinatra (v2.0.4) has taken the stage on 3000 for development with backup from Puma
Puma starting in single mode...
* Version 3.12.0 (ruby 2.6.0-p-1), codename: Llamas in Pajamas
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

第二个开始 ruby test.rb:

Address already in use - bind(2) for 0.0.0.0:3000

您可以在 rescue 块内充实您想要打印到控制台的内容。

这似乎是由 issue with Puma, that is fixed by this PR 引起的。