大型rails应用程序启动时间

时间:2015-06-05 12:16:30

标签: ruby-on-rails ruby heroku

我有一个非常大的rails应用程序,我已经阅读了关于如何减少启动时间的每个帖子,每个都建议减少模型或控制器或宝石,但所有这些都被使用。

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

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

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

2 个答案:

答案 0 :(得分:0)

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

从github项目中查看此sample application.rb file。您应该能够在initialize!范围内扩展class Application < Rails::Application方法。

您可以从第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里面。如果是这种情况,那么你会陷入哪个初始化器?

答案 1 :(得分:-1)

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

我在做什么: 在我的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变量之前初始化的应用程序。