Application load time with large racks
I have a very very large rails app and have read every post on how to reduce load times, each suggesting cut back on tools or controllers or gems, but they are all used.
The problem I'm running into is heroku pushing error code R10 as my app takes over 60 seconds to load.
I tried one, almost successfully. I am trying to run Bundler.require and Application.inialize! in threads (the last thread is waiting for the first completion). The advantage of this is that the thin server boots up almost instantly.
The problem is that when someone makes a request to the application, the initialization process remains incomplete. Any idea how I can achieve this?
source to share
You can take control of the initialization process by extending the method initialize!
to config/application.rb
.
Take a look at the sample application.rb
file from the github project. You must extend the method initialize!
inside the scope class Application < Rails::Application
.
You can use the basic methods from the Rails Initialization Docs under 2.3 railties / lib / rails / application.rb. So, this is what you get if you extend the methods and leave them as default.
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
At this point, you can add print approvals and determine which part you are stuck on. For example, your variable is @initialized
never set to true
? If so, why? You may be stuck inside run_intializers
. If so, what initializer are you getting stuck inside?
source to share
I realized what I am trying to do, it is not possible. So I end the thread.
What I do: In my .rb environment,
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 }
In my environment .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
the middleware I'm using above all the others:
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
But the problem is that Rack :: Server allocates the "app" variable and .start! s server when hit is hit. So no matter what I do, I cannot change the application that was initialized BEFORE this @app variable was populated.
source to share