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:
- I attempt to configure Hutch via an environment variable. For this example,
HUTCH_MQ_EXCHANGE=my-exchange
, which Hutch defaults tohutch
. - During application boot, Rails executes
Bundle.require
followed byDotenv.load
- After Bundler requires Hutch, but before
Dotenv.load
updates theENV
hash, Hutch::Config evaluates the environment and configures itself to use the values inENV
at the time Hutch was required. - 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:
- 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
- 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:
- Programmatically configure Hutch via an initializer
Add this to the top of your Hutch initializer and you should be good to go:Explanation:# config/initializers/hutch.rb Hutch::Config.initialize(Hutch::Config.env_based_config)
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 inHutch::Config
.Hutch::Config.env_based_config
will readENV
when .env_based_config is called and return all the appropriate Hutch configurations defined inENV
. - Declare your ENV configs prior to invoking the
hutch
binaryExplaination: 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 whatbundle exec dotenv hutch
ENV
looks like. This is more similar to what Heroku does when you tell it to run Hutch via aProcfile
, meaningENV
is guaranteed to be up to date prior to your code being executed. You can get similar behavior by invoking Hutch with thedotenv
binary.
Workarounds that do not work
- Require Dotenv as dotenv/rails-now
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
gem 'dotenv-rails', require: 'dotenv/rails-now' gem 'gem-that-requires-env-variables' # like Hutch!
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.