ruby-amqp/hutch

Hutch::Config evaluates environment as soon as Hutch is required

Closed this issue · 1 comments

tldr; I had problems using Hutch with Dotenv. Docs could have been better, and Hutch may be able to avoid this problem with a few changes, but at the end of the day this wasn't really a bug in Hutch.

Context

Ruby version: 2.3.4
Rails version: 4.2.8
Hutch version: 0.24.0

Problem

I ran into a configuration issue with in a Rails application that used Foreman/Dotenv in conjunction with Hutch. At a high level, here's what I saw happening:

  1. I attempt to configure Hutch via an environment variable. For this example, HUTCH_MQ_EXCHANGE=my-exchange, which Hutch defaults to hutch.
  2. During application boot, Rails executes Bundle.require followed by Dotenv.load
  3. After Bundler requires Hutch, but before Dotenv.load updates the ENV hash, Hutch::Config evaluates the environment and configures itself to use the values in ENV at the time Hutch was required.
  4. I go on bit of a goose chase trying to figure out why Hutch ignores my env configs.

Thoughts

Now that I understand Hutch::Config reads the environment at the time it's required, I realize that this is not a bug in Hutch, but rather how my own application's dependencies were interacting with each other. However, I have to wonder if we could improve the situation:

  1. Is there a way we can defer Hutch::Config's evaluation of the environment until it's actually referenced? Lazy evaluation in this case would have resulted in (subjectively) more predictable behavior from someone (in this case, me) not familiar with Hutch internals
  2. What improvements can be made to the README or other documentation to outline how Hutch initializes and loads?

PS: Hutch is great. Thanks for making it! I intend this purely as constructive criticism and I'm happy to draft a PR to help alleviate these rough edges if there's any interest in doing so.


Workarounds

Note: I'm including this for posterity (likely me 6 months from now). As a reminder this does not appear to be a problem with Hutch, just what I figure is a common problem if you're using Hutch with Dotenv.

I found a few different ways to fix the env/hutch load order problems for my use-case, for anyone else who may have run into this gotcha:

  1. Programmatically configure Hutch via an initializer
    Add this to the top of your Hutch initializer and you should be good to go:
    # config/initializers/hutch.rb
    Hutch::Config.initialize(Hutch::Config.env_based_config)
    Explanation: Hutch::Config has two useful methods for re-evaluating ENV and updating the global Hutch::Config singleton: Hutch::Config.initialize will take a hash of configurations and use them to update all configs stored in Hutch::Config. Hutch::Config.env_based_config will read ENV when .env_based_config is called and return all the appropriate Hutch configurations defined in ENV.
  2. Declare your ENV configs prior to invoking the hutch binary
    bundle exec dotenv hutch
    Explaination: This seems pretty obvious in retrospect, but isn't exactly what happens when one uses tools like Dotenv or has code (perhaps a unit test) that changes what ENV looks like. This is more similar to what Heroku does when you tell it to run Hutch via a Procfile, meaning ENV is guaranteed to be up to date prior to your code being executed. You can get similar behavior by invoking Hutch with the dotenv binary.

Workarounds that do not work

  1. Require Dotenv as dotenv/rails-now
      gem 'dotenv-rails', require: 'dotenv/rails-now'
      gem 'gem-that-requires-env-variables' # like Hutch!
    As my problem here was specific to interactions between Hutch and Dotenv, a Dotenv specific solution should have worked out rather well. Turns out this kind of issue is common enough that Dotenv provides a way to ensure that the environment is updated as soon as Dotenv is required, which can be used to avoid the problems I describe entirely so long as you ensure you reference Dotenv prior to whatever gems have a require-time dependency on certain ENV values being set.
    Sadly, this did not work for Hutch. :(

Thanks VERY MUCH for posting the solution! Came across the same thing. A patch to the docs would fix this just nicely, especially since it's a one-liner.