【问题标题】:large rails application boot time大型 Rails 应用程序启动时间
【发布时间】:2015-06-05 12:16:29
【问题描述】:

我有一个非常大的 Rails 应用程序,我已经阅读了那里关于如何减少启动时间的每篇文章,每篇文章都建议减少模型、控制器或 gem,但它们都在使用。

我面临的问题是 heroku 推送 R10 错误代码,因为我的应用需要 60 多秒才能加载。

我一直在尝试一件事,几乎成功了。我正在尝试运行 Bundler.require 和 Application.initialize!在线程中(后线程等待第一个线程完成)。这样做的好处是瘦服务器几乎可以立即启动。

问题是,当有人向应用发出请求时,初始化过程仍然不完整。知道如何实现这一目标吗?

【问题讨论】:

  • 您能否详细说明“初始化过程未完成”?你的意思是初始化永远不会完成吗?还是没有设置一些“初始化”变量?你有错误吗?

标签: ruby-on-rails ruby heroku


【解决方案1】:

您可以通过扩展config/application.rb 中的initialize! 方法来控制初始化过程。

看看这个来自 github 项目的sample application.rb file。您应该能够在class Application < Rails::Application 范围内扩展initialize! 方法。

您可以从第 2.3 节 railties/lib/rails/application.rb 中的Rails Initialization docs 获取基本方法。因此,如果您扩展方法并将它们保留为默认实现,那么您将拥有以下内容。

class Application < Rails::Application
  def initialize!(group=:default) #:nodoc:
    raise "Application has been already initialized." if @initialized
    run_initializers(group, self)
    @initialized = true
    self
  end

  def run_initializers(group=:default, *args)
    return if instance_variable_defined?(:@ran)
    initializers.tsort_each do |initializer|
      initializer.run(*args) if initializer.belongs_to?(group)
    end
    @ran = true
  end
end

此时您可以添加打印语句并确定您遇到的问题。例如,您的@initialized 变量是否从未设置为true?如果是这样,为什么?也许你被困在run_intializers 里面了。如果是这种情况,那么你被困在哪个初始化程序中?

【讨论】:

    【解决方案2】:

    我已经意识到我想要做的事情是不可能的。所以我要结束这个话题了。

    我在做什么: 在我的 environment.rb 中,

    def init_bundler
    
      # If you want your assets lazily compiled in production, use this line
      s = Time.now
      _rails_groups = (ENV["RAILS_GROUPS"]||"").split(",")
      if _rails_groups.length == 1 and _rails_groups.first.to_s == "assets"
        Bundler.require(:assets)  #load ONLY assets .. 
      elsif _rails_groups.length == 1 and _rails_groups.first.to_s == "clock"
        Bundler.require(:clock)  #load ONLY assets .. 
      else
        Bundler.require(:default, *_rails_groups, Rails.env.to_s)
      end
      puts "bundler required in #{Time.now - s}s"
    end
    
    puts "starting t1"
    $_t1 = Thread.new{ init_bundler }
    

    在我的环境中.rb:

    def init_app
      # Initialize the rails application
      puts "initialize started"
      s = Time.now
      Hedgepo::Application.initialize!
      puts "initialize done in #{Time.now - s}s"
    
    end
    
    puts "starting t2"
    $_t2 = Thread.new do 
      loop do 
        if defined?($_t1) and !$_t1.status
          init_app
          break
        else
          puts "waiting for bundler"
        end
        sleep(1)
      end
    end
    

    我使用的中间件高于其他人:

    class MyInit
      def initialize(app)
        @app = app
      end
    
      def call(env)
        loop do 
          if defined?($_t2) and !$_t2.status
            break
          else
            puts "waiting for app init to finish...."
          end
          sleep(1)
        end
        @app.call(env)
      end
    end
    

    但问题是 Rack::Server 分配了一个 'app' 变量并在命中时 .start!s 服务器。因此,无论我做什么,我都无法更改在填充此 @app 变量之前初始化的应用程序。

    【讨论】:

    • 您可以覆盖任何您想要的进程,它是 Ruby,这就是它的美妙之处。您需要做的就是找出@app 的分配位置,并像我在回答中所做的那样扩展该方法。控制这些初始化功能非常简单。
    • 另外,您的回答确实没有解决任何问题。您所做的就是手动调用默认方法。您需要访问方法的范围,而不是简单地调用它们。
    猜你喜欢
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-22
    • 1970-01-01
    • 2013-01-28
    相关资源
    最近更新 更多