我如何通过代码守护 ruby 服务器?

How do I daemonize a ruby server from code?

handler = Rack::Handler::Thin
#driver = Selenium::WebDriver.for :firefox

class RackApp
  def call(env)
    req = Rack::Request.new(env)
    case req.path_info
    when /hello/
      [200, {"Content-Type" => "text/html"}, [render_erb]]
    when /goodbye/
      [500, {"Content-Type" => "text/html"}, ["Goodbye Cruel World!"]]
    else
      [404, {"Content-Type" => "text/html"}, ["I'm Lost!"]]
    end
  end

  def render_erb
    raw = File.read('template/tipsters.html.erb')
    ERB.new(raw).result(binding)
  end
end
handler.run(RackApp.new, {server: 'sfsefsfsef', daemonize: true, pid: "/piddycent.pid"})

puts "hellllllllllllllllllllllllllllllllllllllllllo"

我正在尝试为我的电脑创建一个在浏览器中输出图表的简单应用程序。在瘦服务器被妖魔化后,我正在尝试使用 selenium 导航到本地主机。不幸的是它不会 deamonize,并且 "hellllllllllllllllllllo" 只在我从终端取消进程时打印到终端,也就是说瘦服务器没有守护进程。

问题是选项散列似乎被忽略了。

是的,任何有关 handler.run 为何忽略我的选项哈希的意见都值得赞赏。完全没有错误,它只是忽略了我的选项散列。

根据文档https://www.rubydoc.info/gems/rack/Rack/Server守护进程是一个选项吗?

我认为这里的问题与误解有关。当我们谈论 daemonizing a process 时,我们实际上是在说 "This process will now run itself in the background independent of any other process." 这可以实现,例如,通过分叉一个进程来创建一个新进程。

听起来这就是你打算在这里做的:启动你的 Ruby 应用程序,它启动一个新的 Rack 应用程序,该应用程序分叉到一个单独的进程中,然后 return 控制你的 Ruby 应用程序,这样您现在就可以同时拥有 Rack 应用程序和 Ruby 应用程序 运行,这样您就可以使用 Selenium 浏览您的 Rack 应用程序了。

这不会自动发生。如果您使用 command line. (because you're starting a new process) But there is no automatic process forking 启动您的应用程序,则可以访问 Thin 中的守护进程选项,可能是因为这会导致许多令人困惑的问题。 (即,如果您 运行 您的应用程序一次并在端口 3000 上分叉一个新的瘦服务器,然后您的 Ruby 应用程序终止并且您再次尝试 运行 它,您将已经拥有一个在端口 3000 上分叉瘦服务器 运行ning 并尝试启动一个新服务器将导致错误,因为端口 3000 正在使用中)

本质上,如果你想 运行 一个守护进程的瘦服务器然后使用 thin CLI 启动它。如果您想 运行 在另一个应用程序中使用临时瘦服务器,请按照上述方式启动它。

这似乎引出了真正的答案:您的解释和代码示例表明您实际上并不需要后台的守护进程瘦服务器 运行ning。您想要一个 运行 在单独线程中并且 return 控制主线程的瘦服务器,以便您可以使用 Selenium,并且当您的应用程序终止时,瘦服务器也会终止。

如果我错了,如果你真的想要一个守护进程的瘦服务器,那么你就错了。您应该将瘦服务器视为一个应用程序,将 Selenium 应用程序视为另一个应用程序。 (单独启动和管理它们,而不是作为单个 Ruby 应用程序)

但如果我是对的,那么它应该很简单:

require 'rack'
require 'thin'
require 'httparty' # used for demonstration purposes only

class RackApp
  def call(env)
    case Rack::Request.new(env).path_info
    when //
      [200, {"Content-Type" => "text/html"}, 'Hello World']
    end
  end
end

threads = []

# First start the Thin server
threads << Thread.new { Rack::Handler::Thin.run(RackApp.new) }

# Then sleep long enough for it to start before making an HTTP request
threads << Thread.new { sleep 2; puts HTTParty.get('http://localhost:8080/').response.body }

threads.each(&:join)

puts 'Back in the main thread'

控制台的输出是:

Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:8080, CTRL+C to stop
Hello World

您需要将 HTTParty.get 调用替换为对 Selenium 的调用。

这可能不是您想要的确切解决方案,因为在您点击 ^C 之前您不会看到 Back in the main thread,即使 Selenium 线程已经完成了它需要做的所有工作,因为细线程仍然是 运行ning:

Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:8080, CTRL+C to stop
Hello World
^CStopping ...
Back in the main thread

如果您希望 Ruby 应用程序在 Selenium 工作完成后终止,您可以将其修改为如下内容:

Thread.new { Rack::Handler::Thin.run(RackApp.new) }

selenium_thread = Thread.new { sleep 2; puts HTTParty.get('http://localhost:8080/').response.body }
selenium_thread.join

puts 'Back in the main thread'

然后您会看到类似这样的内容,其中 Ruby 应用程序在打印 Back in the main thread:

后立即终止
Thin web server (v1.7.2 codename Bachmanity)
Maximum connections set to 1024
Listening on localhost:8080, CTRL+C to stop
Hello World
Back in the main thread