在同一脚本中启动并调用Ruby HTTP服务器
我想知道如何启动Ruby Rack应用程序(例如Sinatra)并在同一脚本中使用Net :: HTTP或类似方法调用它。 我可以做点什么……
require 'sinatra/base' require 'net/http' t = Thread.new do class App 'localhost', :port => 1234 end sleep 2 puts Net::HTTP.start('localhost', 1234) { |http| http.get('/') }.body t.join puts 'Bye!'
…但是,等待Thin启动时,睡眠两秒钟并不是最佳选择。 我需要的是当服务器启动时或某人有任何其他建议时的某种回调?
如果你看看run!
在base.rb的sinatra源代码中你会看到这个:
def run!(options={}) ... handler.run self, :Host => bind, :Port => port do |server| [:INT, :TERM].each { |sig| trap(sig) { quit!(server, handler_name) } } set :running, true end ... end
这里没有办法附加回调。 但! 如您所见:running
设置在服务器启动后更改。
因此,简单的解决方案似乎是让一个线程在一个小的轮询循环中观察App.settings.running
(每隔500毫秒或沿着这些行的东西)。 一旦running
是真的,你可以安全地做你的东西。
编辑:改进版本,有一点猴子修补善良。
添加after_running回调给Sinatra:
class Sinatra::Base # Redefine the 'running' setting to support a threaded callback def self.running=(isup) metadef(:running, &Proc.new{isup}) return if !defined?(after_running) return if !isup Thread.new do Thread.pass after_running end end end class App < Sinatra::Base set :after_running, lambda { puts "We're up!" puts Net::HTTP.start('localhost', 1234) { |http| http.get('/') }.body puts "Done" } get '/' do 'Hi!' end end App.run! :host => "localhost", :port => 1234
run!
在当前的Sinatra版本中,需要一个在启动应用程序时调用的块。
使用该回调您可以这样做:
require 'thread' def sinatra_run_wait(app, opts) queue = Queue.new thread = Thread.new do Thread.abort_on_exception = true app.run!(opts) do |server| queue.push("started") end end queue.pop # blocks until the run! callback runs end sinatra_run_wait(TestApp, :port => 3000, :server => 'webrick')
这对于WEBrick来说似乎是可靠的,但是当使用Thin时,在服务器接受连接之前,有时仍会调用回调。
我会使用一个容量为1的信号量(参见Ruby Semaphores? )来执行此任务:
主线程:
- 获取信号量
- 产生新线程
- 获取信号量(将阻塞直到产生的线程释放)
产生的Web服务器线程:
- App.run!
- 释放信号量