Initializers aren't run on gem dependency failure

9 views
Skip to first unread message

Sandofsky

unread,
Aug 12, 2008, 11:07:37 PM8/12/08
to Ruby on Rails: Core
Let's say you've added a gem dependency with config.gem, but your gem
isn't installed or Rails doesn't see it. Like the json gem, which one
of our unfortunate Windows developers has installed but Rails doesn't
see. (I hear it's a Windows issue, but I don't use it.)

When you start your mongrel, you get a warning that you're missing
gems. "That's ok. My app has a graceful fallback." Then your app will
throw seemingly random errors. After a bit of troubleshooting, you
learn Rails is skipping your after_initialize block and config/
initializers/*.rb files if it fails to load any gems.

Unless someone can explain the reasoning, I think this is a bug, and
I've made the patch to fix it.

http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/814-initializers-aren-t-run-on-gem-dependency-failure

I couldn't find any tests that check the config/initializers/ files
are run, so I've added one.

Looking for feedback.

Mislav Marohnić

unread,
Aug 13, 2008, 12:58:55 AM8/13/08
to rubyonra...@googlegroups.com
I don't see a reason for the old behavior, and I do agree that, if we're continuing with initialization instead of hard failing, it shouldn't skip loading initializers and instantiating AR observers.

The question we should be asking ourselves is: do we really want to allow the app to fully initialize if it can't load gem dependencies? Can we expect it to work this way?

I say no. A Rails app should fail as soon as a requirement that is not met is found: a required file, gem, plugin or similar. Opinions?

# Mislav

Chad Woolley

unread,
Aug 13, 2008, 1:11:07 AM8/13/08
to rubyonra...@googlegroups.com
On Tue, Aug 12, 2008 at 9:58 PM, Mislav Marohnić
<mislav....@gmail.com> wrote:
> The question we should be asking ourselves is: do we really want to allow
> the app to fully initialize if it can't load gem dependencies? Can we expect
> it to work this way?
> I say no. A Rails app should fail as soon as a requirement that is not met
> is found: a required file, gem, plugin or similar. Opinions?

I agree. If a dependency is not met, exit immediately with an error.
If the missing dependency isn't REALLY a problem in some situations,
then encode that conditionality using ruby - check the platform,
environment, shell out to run a command, whatever you need. Isn't why
we are configuring the gems in ruby, to have that flexibility and
control?

-- Chad

Damian Janowski

unread,
Aug 13, 2008, 2:45:45 AM8/13/08
to rubyonra...@googlegroups.com
2008/8/13 Chad Woolley <thewoo...@gmail.com>:

> I agree. If a dependency is not met, exit immediately with an error.
> If the missing dependency isn't REALLY a problem in some situations,
> then encode that conditionality using ruby - check the platform,
> environment, shell out to run a command, whatever you need. Isn't why
> we are configuring the gems in ruby, to have that flexibility and
> control?

At least that was the reason for dumping my original config/gems.yml approach :)

Hongli Lai

unread,
Aug 13, 2008, 5:41:58 AM8/13/08
to Ruby on Rails: Core
On Aug 13, 6:58 am, "Mislav Marohnić" <mislav.maroh...@gmail.com>
wrote:
> I don't see a reason for the old behavior, and I do agree that, if we're
> continuing with initialization instead of hard failing, it shouldn't skip
> loading initializers and instantiating AR observers.
> The question we should be asking ourselves is: do we really want to allow
> the app to fully initialize if it can't load gem dependencies? Can we expect
> it to work this way?
>
> I say no. A Rails app should fail as soon as a requirement that is not met
> is found: a required file, gem, plugin or similar. Opinions?

I vote for yes, because:
1. Not all dependencies are hard dependencies. For example, an app
that I'm working on supports syntax highlighting through 'uv', but
it'll gracefully fallback if uv is not available (e.g. when being run
on JRuby, because uv relies on a native extension).
2. A few people (I think about 3) have reported this problem as a
Phusion Passenger bug. So it should be apparent that people don't
expect the current behavior.

That said, I think it would be better to allow one to specify required
gems and optional gems. A while ago my co-developer pulled the latest
version of our application and asked me why it would crash when he
visits a certain URI. Turns out that he didn't have a gem installed,
and missed the startup warning.

The following situation would be ideal:
- Hard gem requirements should fail hard, during startup.
- Soft gem requirements should only print a warning. Like: config.gem
'something', :optional => true

Chad Woolley

unread,
Aug 13, 2008, 7:50:38 AM8/13/08
to rubyonra...@googlegroups.com
On Tue, Aug 12, 2008 at 11:45 PM, Damian Janowski
<damian....@gmail.com> wrote:
> At least that was the reason for dumping my original config/gems.yml approach :)

Yes, but you get the best of both worlds (dynamic control and
decoupling dependencies from app) if you run your YAML through ERB :)

Rob Sanheim

unread,
Aug 13, 2008, 10:06:40 AM8/13/08
to rubyonra...@googlegroups.com
On Wed, Aug 13, 2008 at 12:58 AM, Mislav Marohnić
<mislav....@gmail.com> wrote:
> I don't see a reason for the old behavior, and I do agree that, if we're
> continuing with initialization instead of hard failing, it shouldn't skip
> loading initializers and instantiating AR observers.
> The question we should be asking ourselves is: do we really want to allow
> the app to fully initialize if it can't load gem dependencies? Can we expect
> it to work this way?
> I say no. A Rails app should fail as soon as a requirement that is not met
> is found: a required file, gem, plugin or similar. Opinions?
> # Mislav

Agreed. It always seemed strange to me that you can load your app
even if you are missing gems.

Maybe there should be a way to specify optional dependencies, but the
default should be to fail fast if a gem is missing.

- Rob

Chris Kampmeier

unread,
Aug 13, 2008, 3:46:56 PM8/13/08
to Ruby on Rails: Core
On Aug 12, 8:07 pm, Sandofsky <sandof...@gmail.com> wrote:
> When you start your mongrel, you get a warning that you're missing
> gems. "That's ok. My app has a graceful fallback." Then your app will
> throw seemingly random errors. After a bit of troubleshooting, you
> learn Rails is skipping your after_initialize block and config/
> initializers/*.rb files if it fails to load any gems.

Just from watching the commits fly by, I thought this was already
fixed in edge? http://github.com/rails/rails/commit/1edb5c85b5

Sandofsky

unread,
Aug 13, 2008, 7:13:20 PM8/13/08
to Ruby on Rails: Core
I've written a new patch that implements this behavior, and includes
my old patch.

http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/824-make-gem-dependency-optional

It defaults to optional being false, meaning your app will fail on
start. If you set :optional => true, the app will only print a warning
if the gem is missing.

Looking for +1's.

Chad Woolley

unread,
Aug 13, 2008, 8:34:08 PM8/13/08
to rubyonra...@googlegroups.com
2008/8/13 Sandofsky <sand...@gmail.com>:

>
> I've written a new patch that implements this behavior, and includes
> my old patch.
>
> http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/824-make-gem-dependency-optional

-1 on this. This should be thought through more.

First, there is now the standard "development" gem property which is
now in RubyGems 1.2.0 (see gem install --help). This is already a way
of specifying gems which are only required in development, but not to
run the app in production/runtime. How would an "optional" flag
relate to this?

Also, what does it mean for a dependency to be "optional"? If it
isn't required sometime, somewhere, for something, it should not be a
dependency. The when, where, and why is completely dependent on the
situation. That's why this should be handled with custom ruby
conditional code - based on platform, RAILS_ENV, hostname, whatever.
In other words, no dependency is ever "optional" - someone must need
it, otherwise it would not be a dependency.

So, I think that this should be handled by leveraging the standard
support which is already in Rubygems, and allow the config.gems to
pass through the --development option to the underlying gem install
command. Anything else that doesn't fall into the current standard
development/runtime category should be handled with custom
conditionals on a per-app basis.

-- Chad

Assaf Arkin

unread,
Aug 13, 2008, 9:38:04 PM8/13/08
to rubyonra...@googlegroups.com
On Wed, Aug 13, 2008 at 5:34 PM, Chad Woolley <thewoo...@gmail.com> wrote:
>
> 2008/8/13 Sandofsky <sand...@gmail.com>:
>>
>> I've written a new patch that implements this behavior, and includes
>> my old patch.
>>
>> http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/824-make-gem-dependency-optional
>
> -1 on this. This should be thought through more.
>
> First, there is now the standard "development" gem property which is
> now in RubyGems 1.2.0 (see gem install --help). This is already a way
> of specifying gems which are only required in development, but not to
> run the app in production/runtime. How would an "optional" flag
> relate to this?

In my case the difference between production and development is that
development also uses gems like rspec, faker, annotate-models. These
are not necessary for running in production. Those are specified
separately in config/environments/development.rb. That, however, has
nothing to do with gem development dependencies. These dependencies
do not interest the app under any condition, it only needs these gems
and their runtime dependencies.

>
> Also, what does it mean for a dependency to be "optional"? If it
> isn't required sometime, somewhere, for something, it should not be a
> dependency. The when, where, and why is completely dependent on the
> situation. That's why this should be handled with custom ruby
> conditional code - based on platform, RAILS_ENV, hostname, whatever.
> In other words, no dependency is ever "optional" - someone must need
> it, otherwise it would not be a dependency.

A lot of times optional means "use it if it's there, don't bother me
if it's not", which is different from only using a gem in a particular
setup. Uv is a good example, it's painful to install and not
supported on JRuby, so you would want to disable this dependency when
running on JRuby, but also make it optional in other conditions.

Assaf

Hongli Lai

unread,
Aug 14, 2008, 5:42:25 AM8/14/08
to Ruby on Rails: Core
On Aug 14, 2:34 am, "Chad Woolley" <thewoolley...@gmail.com> wrote:
> -1 on this.  This should be thought through more.
>
> First, there is now the standard "development" gem property which is
> now in RubyGems 1.2.0 (see gem install --help).  This is already a way
> of specifying gems which are only required in development, but not to
> run the app in production/runtime.  How would an "optional" flag
> relate to this?
>
> Also, what does it mean for a dependency to be "optional"?  If it
> isn't required sometime, somewhere, for something, it should not be a
> dependency.  The when, where, and why is completely dependent on the
> situation.  That's why this should be handled with custom ruby
> conditional code - based on platform, RAILS_ENV, hostname, whatever.
> In other words, no dependency is ever "optional" - someone must need
> it, otherwise it would not be a dependency.

Being able to specify development gems would be very useful. For
example, if you use RSpec as testing framework then you only need
RSpec to be installed on the development machine, not the production
machine (unless you want to run the tests on the production machine as
well).

However, that's not the same thing as optional gems. Here's a concrete
example of an optional gem:
One of my applications use the 'uv' gem for syntax highlighting code.
But it's not a hard requirement: at runtime, my application will check
whether Uv is available, and if not, then the application will still
work, it just won't do syntax highlighting.

Uv depends on a native extension. If any members in my development
team can't compile this native extension for whatever reason, then I
still want them to be able to help with development even though syntax
highlighting doesn't work.

Michael Koziarski

unread,
Aug 14, 2008, 6:21:37 AM8/14/08
to rubyonra...@googlegroups.com
> Being able to specify development gems would be very useful. For
> example, if you use RSpec as testing framework then you only need
> RSpec to be installed on the development machine, not the production
> machine (unless you want to run the tests on the production machine as
> well).

You *should* be able to achieve this by using config.gem in
development.rb. If this doesn't work it's a bug and we should fix it.

> However, that's not the same thing as optional gems. Here's a concrete
> example of an optional gem:

We have cases of this in the rails codebase, but typically they rescue
LoadError and set up some stub versions of the relevant libraries.
i.e. it's not enough to just rescue the failed load, some values have
to be set up so the application knows what to do. Perhaps you require
an alternative gem, or you just stub out a few constants and methods
or set a global variable like $uv_installed = false.

I'm really not sold on doing this through config.gem as there's just
no simple 'else' case here.


--
Cheers

Koz

Chad Woolley

unread,
Aug 14, 2008, 1:44:13 PM8/14/08
to rubyonra...@googlegroups.com
On Wed, Aug 13, 2008 at 6:38 PM, Assaf Arkin <as...@labnotes.org> wrote:
> A lot of times optional means "use it if it's there, don't bother me
> if it's not", which is different from only using a gem in a particular
> setup. Uv is a good example, it's painful to install and not
> supported on JRuby, so you would want to disable this dependency when
> running on JRuby, but also make it optional in other conditions.

I still think this would be better handled via custom application
code. For example, never do it if platform is Jruby, or if some other
app-specific flag is set.

The app-specific flag could be a constant or environment variable
which says to either use or not use the dependency (depending on which
is the most common case). If you don't like environment variables,
put it as a constant in a file that is attempted to be loaded, but
ignored and never checked into source control. A developer-specific
config file, sort of like database.yml if you don't check it in.

Chad Woolley

unread,
Aug 14, 2008, 2:56:58 PM8/14/08
to rubyonra...@googlegroups.com
On Thu, Aug 14, 2008 at 3:21 AM, Michael Koziarski
<mic...@koziarski.com> wrote:
> You *should* be able to achieve this by using config.gem in
> development.rb. If this doesn't work it's a bug and we should fix it.

Cool. Good to know. I never actually use config.gems myself, since
there are (cough cough geminstaller) more fully-featured alternatives.
Just Kidding :)

-- Chad

Reply all
Reply to author
Forward
0 new messages