【问题标题】:How to determine if Rails is running from CLI, console or as server?如何确定 Rails 是从 CLI、控制台还是作为服务器运行?
【发布时间】:2012-11-10 11:55:27
【问题描述】:

我有一个middleware for announcing my application on the local network app using Bonjour,但它也会在从 rake 或通过控制台调用 Rails 时宣布该服务。

我想排除这些情况,并且只在 Rails 作为服务器运行时使用 Bonjour 中间件。

中间件配置接受 proc 在某些条件下使用 proc 排除中间件:

config.middleware.insert_before ActionDispatch::Static, Rack::SSL, :exclude => proc { |env| 
  env['HTTPS'] != 'on' 
}

但是如何确定 Rails 是从 CLI、控制台还是作为服务器调用的?

【问题讨论】:

    标签: ruby-on-rails rack rack-middleware


    【解决方案1】:

    使用pry 查看Rails 模块显示可以像这样检测控制台调用:

    Rails.const_defined? 'Console'
    

    还有这样的服务器调用:

    Rails.const_defined? 'Server'
    

    【讨论】:

    • 有趣的是,这仅在调用“rails s”或“rails c”命令时才有效。如果您通过不同的命令(例如,“unicorn_rails”)运行服务器,则这些常量永远不会被定义。 Rails::Server 看起来像是被定义为命令解析过程的一部分,尽管它继承自 ::Rack::Server。
    • 这对我来说不适用于 Rails 4,即使使用 rails c。我在控制台中定义了服务器和控制台。
    • @MarkTabler @DanHerman 如果用独角兽启动 Rails 试试这个? (Rails.const_defined? 'Server') || ($0.include? 'unicorn')
    • Rails::Server 仍然在像 rails g migration 这样的生成器脚本中定义。
    • Server 在使用乘客时没有定义
    【解决方案2】:

    超级有用。谢谢@crishoj。

    我想更仔细地检查 Console 对象以解决我正在处理的另一个问题,并发现可以使用 Rails::Console 访问 Console 常量,因此另一个检查选项是使用:

    defined? Rails::Console
    defined? Rails::Server
    

    【讨论】:

    • Rails::Server 仍然在像 rails g migration 这样的生成器脚本中定义。此外,Rails::Console 是在运行 rails s 时定义的。
    【解决方案3】:

    使用带有或不带有 Puma/Passenger 等应用服务器的 Rails 5,以下是确定应用运行方式的三种方法:

    # We are running in a CLI console
    defined?(Rails::Console)
    
    # We are running as a Rack application (including Rails)
    caller.any?{|l| l =~ %r{/config.ru/}}
    
    # We are running as a CLI console
    caller.any?{|l| l =~ %r{/lib/rake/task.rb:\d+:in `execute'}}
    

    【讨论】:

    • caller.any?{|l| l =~ %r{/config.ru/}} -- 不应该删除尾部斜杠吗?固定线路为:caller.any? {|l| l =~ %r"/config\.ru" }
    • 稍微干净一点的版本:caller.grep(%r{/config.ru}).any?
    【解决方案4】:

    每个命令的环境总结。

    我发现现有答案不完整、多余或不详尽。所以这里是每个命令的表格格式以及生成的环境是什么样的。

    导轨 4.2

    | Command                            |  Rails.const_defined?( "Console" )  |  Rails.const_defined?( "Server" )  |               ARGV              |
    |------------------------------------|-------------------------------------|------------------------------------|---------------------------------|
    | `rake db:migrate:status`           |  false                              |  true                              |  ["db:migrate:status"]          |
    | `rails console`                    |  true                               |  true                              |  []                             |
    | `rails server`                     |  false                              |  true                              |  []                             |
    | `rails g migration new_migration`  |  false                              |  true                              |  ["migration", "new_migration"] |
    | `rails r "puts 'Hi'"`              |  false                              |  true                              |  []                             |
    

    您可以看到,仅检查定义为Rails 常量的“服务器”不会捕获生成器,例如rails g migration。您需要检查ARGV 来执行此操作。

    我希望这会有所帮助。我只能立即访问 Rails 4.2,但可以随意添加其他 Rails 版本的部分,以及添加任何需要“捕获”的附加命令。

    【讨论】:

    • 在 Rails 5.2 中,Rails.const_defined?( "Server" ) 仅在运行 rails server 时为 true。当服务器不是使用 Rails 命令启动时,额外检查程序名称会有所帮助:Rails.const_defined?(:Server) || $PROGRAM_NAME.include?('puma')
    • 实际上,对于 Puma,最好另外检查 Puma::Server: Rails.const_defined?(:Server) || ($PROGRAM_NAME.include?('puma') && Puma.const_defined?(:Server))
    【解决方案5】:

    Rails 5 在Passenger 下运行时未定义“服务器”。

    我发现的最佳解决方案是this 答案的变体:

    if %w(rails rake).include?(File.basename($0))
       <console or runner>
    else
       <server>       
    end
    

    【讨论】:

    • Rails::Server 仍然在像 rails g migration 这样的生成器脚本中定义。此外,Rails::Console 是在运行 rails s 时定义的。
    【解决方案6】:

    在我们的项目中,我必须在 boot.rb 中检测控制台模式,为此我使用了:

    in_console = (ARGV & ['c', 'console']).any?
    

    不是万无一失的解决方案,但对于我们的用例来说已经足够了。

    【讨论】:

    • 感谢您向我介绍ARGV。这是检测何时调用rails g 而不是rails s 的唯一方法。
    【解决方案7】:

    这是我在乘客/美洲狮上检测 sidekiq 或正在运行的服务器的版本。鉴于前面的答案,不能 100% 确定它在所有情况下都能正常工作(我还没有测试过运行 rails runner 或 rake 任务时的情况)

    @running_app = begin
      if defined?(Rails::Console)
        'Console'
      elsif Sidekiq.server?
        'Worker'
      elsif defined?(::PhusionPassenger) || defined?(Rails::Server) 
        'Server'
      else
        nil # unknown
      end
    end
    

    【讨论】:

      【解决方案8】:

      对于帕德里诺:

      控制台检查:

      if Padrino::constants.include? :Cli
          #your code
      end
      

      服务器检查:

      if !Padrino::constants.include? :Cli
          #your code
      end
      

      【讨论】:

        猜你喜欢
        • 2016-10-27
        • 2012-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-06
        • 1970-01-01
        相关资源
        最近更新 更多