####david.antaramian in @elixir-lang slack, #beginners [2:11 PM]
Just in case you need it for reference in the future, this is the problem we normally see people run into: People will sometimes have called the environment variable during a module attribute assignment. Like the following:
defmodule MyAPP.APIClient do
@api_key System.get_env("API_KEY")
end
or more commonly, they'll call the System.get_env/1
inside a config file and then assign the result to a module attribute:
# config/config.exs
config :my_app, :api_client,
api_key: System.get_env("API_KEY")
# lib/my_app/api_client.ex
defmodule MyAPP.APIClient do
@api_key Application.get_env(:my_app, :api_client)[:api_key]
end
The trick is that Elixir is a compiled language, and that module attribute are evaluated at compile time. So whatever the value of that environment variable is at compile time (or nil if it doesn't exist), becomes the value used throughout the file for that attribute until the module gets recompiled. I've seen this issue with people running on Heroku where they expect to have their API Key be fetched dynamically, but because the environment variable wasn't present when the slug was compiled, the code always just reports nil
as the API key.
For this reason, it's useful to use scripts like this one from Bitwalker: https://gist.github.com/bitwalker/a4f73b33aea43951fe19b242d06da7b9
This makes the environment variable be fetched at the last minute when used correctly.
And it's release-safe. System.get_env/1
(or any other function calls) are not release safe in config.exs
Is there a solution that would work for non-user applications such as
exq
orecto
? To my knowledge, you can only configure them viasys.config
in a compiled application. I know of an alternative that uses Erlang options but I was wondering if you knew of a cleaner approach.EDIT: I also know about
RELX_REPLACE_OS_VARS
, which only works with string values. This falls apart when dealing with ports or pool size, for example.