Skip to content

Commit

Permalink
If an app failed to start because of a LoadError, then correctly relo…
Browse files Browse the repository at this point in the history
…ad RubyGems caches so that newly installed gems can be found.
  • Loading branch information
FooBarWidget committed Mar 28, 2008
1 parent 533a6cc commit 824c0fd
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/passenger/application.rb
Expand Up @@ -52,7 +52,7 @@ def self.detect_framework_version(app_root)
# If this error was reported before, then the cache might be out of
# date because the Rails version may have been installed now.
# So we reload the cache and try again.
Gem.cache.refresh!
Gem.refresh_all_caches!
found_version = Gem.cache.search('rails', gem_version_spec).map do |x|
x.version.version
end.sort.last
Expand Down
12 changes: 12 additions & 0 deletions lib/passenger/framework_spawner.rb
Expand Up @@ -253,6 +253,10 @@ def preload_rails
end

def handle_spawn_application(app_root, lower_privilege, lowest_user)
if @refresh_gems_cache
Gem.refresh_all_caches!
@refresh_gems_cache = false
end
lower_privilege = lower_privilege == "true"
@spawners_lock.synchronize do
spawner = @spawners[app_root]
Expand All @@ -263,6 +267,14 @@ def handle_spawn_application(app_root, lower_privilege, lowest_user)
rescue ArgumentError, AppInitError, ApplicationSpawner::Error => e
client.write('exception')
client.write_scalar(marshal_exception(e))
if e.child_exception.is_a?(LoadError)
# A source file failed to load, maybe because of a
# missing gem. If that's the case then the sysadmin
# will install probably the gem. So next time an app
# is launched, we'll refresh the RubyGems cache so
# that we can detect new gems.
@refresh_gems_cache = true
end
return
end
@spawners[app_root] = spawner
Expand Down
13 changes: 13 additions & 0 deletions lib/passenger/spawn_manager.rb
Expand Up @@ -120,6 +120,10 @@ def cleanup
def handle_spawn_application(app_root, lower_privilege, lowest_user)
lower_privilege = lower_privilege == "true"
app = nil
if @refresh_gems_cache
Gem.refresh_all_caches!
@refresh_gems_cache = false
end
begin
app = spawn_application(app_root, lower_privilege, lowest_user)
rescue ArgumentError => e
Expand All @@ -133,6 +137,15 @@ def handle_spawn_application(app_root, lower_privilege, lowest_user)
(e.child_exception.is_a?(UnknownError) && e.child_exception.real_class_name =~ /^ActiveRecord/)
send_error_page(client, 'database_error', :error => e,
:app_root => app_root)
elsif e.child_exception.is_a?(LoadError) ||
(e.child_exception.is_a?(UnknownError) && e.child_exception.real_class_name == "MissingSourceFile")
# A source file failed to load, maybe because of a
# missing gem. If that's the case then the sysadmin
# will install probably the gem. So next time an app
# is launched, we'll refresh the RubyGems cache so
# that we can detect new gems.
@refresh_gems_cache = true
send_error_page(client, 'load_error', :error => e, :app_root => app_root)
else
send_error_page(client, 'app_init_error', :error => e,
:app_root => app_root)
Expand Down
46 changes: 46 additions & 0 deletions lib/passenger/templates/load_error.html.erb
@@ -0,0 +1,46 @@
<% layout 'error_layout', :title => "Ruby on Rails application could not be started" do %>
<h1 class="error_title">Ruby on Rails application could not be started</h1>
<div id="content">

A source file that the application requires, is missing.
<ul>
<li class="first">
<div class="container">
<div class="content">
It is possible that you didn't upload your application files correctly.
Please check whether all your application files are uploaded.
</div>
</div>
</li>
<li class="last">
<div class="container">
<div class="content">
A required library may not installed. Please install all libraries
that this application requires.
</div>
</div>
</li>
</ul>
Further information about the error may have been written to the
application's log file. Please check it in order to analyse the problem.

<dl>
<dt>Error message:</dt>
<dd><%=h @error.child_exception.message %></dd>

<dt>Exception class:</dt>
<dd><%=h @error.child_exception.class %></dd>

<dt>Application root:</dt>
<dd>
<tt class="filename"><%=h @app_root %></tt>
</dd>

<dt>Backtrace:</dt>
<dd>
<%= backtrace_html_for(@error.child_exception) %>
</dd>
</dl>

</div>
<% end %>
11 changes: 11 additions & 0 deletions lib/passenger/utils.rb
Expand Up @@ -194,6 +194,17 @@ def recv_io
end
end

module Gem
# Refresh all RubyGems caches so that newly installed gems can be found.
def self.refresh_all_caches!
# Why doesn't RubyGems already provide an API for this?
cache.refresh!
MUTEX.synchronize do
@searcher = nil
end
end
end

module GC
if !respond_to?(:copy_on_write_friendly?)
# Checks whether the current Ruby interpreter's garbage
Expand Down

0 comments on commit 824c0fd

Please sign in to comment.