[英]Start and call Ruby HTTP server in the same script
I wonder how I could start a Ruby Rack application (such as Sinatra) and call it with Net::HTTP or similar in the same script.我想知道如何启动 Ruby 机架应用程序(例如 Sinatra)并在同一脚本中使用 Net::HTTP 或类似名称调用它。 Of couse I could do something like...当然,我可以做类似...
require 'sinatra/base'
require 'net/http'
t = Thread.new do
class App < Sinatra::Base
get '/' do
'Hi!'
end
end
App.run! :host => 'localhost', :port => 1234
end
sleep 2
puts Net::HTTP.start('localhost', 1234) { |http| http.get('/') }.body
t.join
puts 'Bye!'
...but it doesn't feel optimal to sleep for two seconds, waiting for Thin to start. ...但是睡两秒钟,等待 Thin 开始,感觉并不理想。 What I need is some kind of callback when the server has started or does anybody have any other suggestions?我需要的是服务器启动时的某种回调,或者是否有人有任何其他建议?
run!
in current Sinatra versions takes a block that is called when the app is started.在当前的 Sinatra 版本中,应用程序启动时会调用一个块。
Using that callback you can do this:使用该回调,您可以执行以下操作:
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')
This seems to be reliable for WEBrick, but when using Thin the callback is still sometimes called a little bit before the server accepts connections.这对于 WEBrick 来说似乎是可靠的,但是当使用 Thin 时,有时在服务器接受连接之前仍然会调用一些回调。
If you look at the run!
如果你看run!
method in the sinatra source in base.rb you will see this: 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
There is no way to attach callbacks around here.这里没有办法附加回调。 BUT!但! as you see the :running
setting is changed once the server is up.如您所见,一旦服务器启动,就会更改:running
设置。
So, the simple solution seems to be to have a thread watch App.settings.running
in a small polling loop (every 500ms or something along those lines).因此,简单的解决方案似乎是让一个线程在一个小的轮询循环中监视App.settings.running
(每 500 毫秒或类似的东西)。 Once running
is true you can safely do your stuff.一旦running
是真的,你就可以安全地做你的事情了。
Edit: improved version, with a bit of monkey patching goodness.编辑:改进版本,带有一点猴子修补的优点。
Adding an after_running callback to Sinatra:向 Sinatra 添加 after_running 回调:
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
I would use a semaphore (cf. Ruby Semaphores? ) with a capacity of 1 for this task:我会为此任务使用容量为 1 的信号量(参见Ruby 信号量? ):
Main thread:主线程:
Spawned web server thread:衍生 web 服务器线程:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.