【问题标题】:Execute code once Sinatra server is runningSinatra 服务器运行后执行代码
【发布时间】:2016-08-09 18:30:09
【问题描述】:

我有一个包含在Sinatra::Base 中的 Sinatra 应用程序,我想在服务器启动后运行一些代码,我应该怎么做?

这是一个例子:

require 'sinatra'
require 'launchy'

class MyServer < Sinatra::Base
  get '/' do
    "My server"
  end

  # This is the bit I'm not sure how to do
  after_server_running do
    # Launches a browser with this webapp in it upon server start
    Launchy.open("http://#{settings.host}:#{settings.port}/")
  end
end

有什么想法吗?

【问题讨论】:

  • 您可能需要更具体一些才能获得帮助。
  • 你可能是对的 - 我认为这是不言自明的!让我们看看这些修改有什么帮助
  • 这不是你问的,但你应该要求sinatra/base,而不是sinatra。来自sinatrarb.com/…:“您的文件应该需要 sinatra/base 而不是 sinatra;否则,所有 Sinatra 的 DSL 方法都会导入到主命名空间中。”

标签: ruby sinatra


【解决方案1】:

使用配置块不是正确的方法。每当您加载文件时,都会运行命令。

尝试扩展run!

require 'sinatra'
require 'launchy'

class MyServer < Sinatra::Base

  def self.run!
    Launchy.open("http://#{settings.host}:#{settings.port}/")
    super
  end

  get '/' do
    "My server"
  end
end

【讨论】:

  • 如果您希望代码在启动后运行,您可能希望在方法中首先调用super
  • 此外,这比使用configure 阻止您在服务器启动后运行获取代码要好,但仅适用于内置服务器 - 如果您使用例如rackupthin start.
  • @matt 实际上,如果您在 super 之后调用 Launchy,它将永远无法到达,我试过了。 settings.host 效果不佳,我将其替换为 localhost,因为我仅在本地使用它。
  • 好点。似乎没有可靠的方法在服务器启动后运行代码,至少在 Sinatra 内部是这样。
【解决方案2】:

我就是这样做的;基本上在单独的线程中运行 sinatra 或其他代码:

require 'sinatra/base'

Thread.new { 
  sleep(1) until MyApp.settings.running?
  p "this code executes after Sinatra server is started"
}
class MyApp < Sinatra::Application
  # ... app code here ...

  # start the server if ruby file executed directly
  run! if app_file == $0
end

【讨论】:

    【解决方案3】:

    如果您正在使用 Rack(您可能是),我刚刚发现有一个可以在 config.ru 中调用的函数(从技术上讲,它是 Rack::Builder 的实例方法),它可以让您在服务器已启动。它被称为warmup,这是记录在案的用法示例:

    warmup do |app|
      client = Rack::MockRequest.new(app)
      client.get('/')
    end
    
    use SomeMiddleware
    run MyApp
    

    【讨论】:

    • 这非常适合原始问题中的 Launchy.open() 调用。尽管首先检查 ENV['RACK_ENV'] == "development" 可能是个好主意,因为您可能不希望在生产环境中运行。
    【解决方案4】:

    stackoverflow 中对这个问题的唯一有效答案(被问了 3-4 次)是由 levinalex on Start and call Ruby HTTP server in the same script 给出的,我引用:

    run! in current Sinatra versions 接受一个在应用启动时调用的块。

    使用该回调,您可以这样做:

    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 时,有时仍然会在服务器接受连接之前调用回调。

    【讨论】:

    • 我很想理解为什么你会说它是唯一有效的答案,而你还说它只对 webrick 可靠工作(这真的不打算在开发人员之外使用,即使那样效用有限)。您能否详细说明为什么其他答案不起作用?
    • 我看到的所有其他解决方案都是 hacky。这是唯一依赖于(很少)保证正在使用的框架的解决方案。 Sinatra 在“启动”时将传递server 对象,因此我们知道应用程序已启动。由网络服务器引起的问题将出现在任何其他 hacky 解决方案(包括上面介绍的解决方案)中。
    猜你喜欢
    • 2015-08-30
    • 2023-03-08
    • 1970-01-01
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    相关资源
    最近更新 更多