vrod
Forgive me for maybe a noob question. I am reading much about configuration – maybe this in Elixir is one of the most confusing things? I read this Configuring your Elixir Application at Runtime with Vapor | AppSignal Blog and it says “if it can be set at runtime, it should be set at runtime.” This makes much sense to me – this is how other languages work with .env files – but maybe the comparison is not fair with dynamic languages?
My question is what things can not be runtime config? I imagine a very simple setup from working with PHP where there was only 1 config and 2 .env files (regular .env and a .test.env) and the test suite would know to use the .test.env. But dynamic languages do not have the same concerns. I am thinking maybe a config for a module name like saying which HTTP client the app should use. A system ENV maybe has string for “HTTPoison”, but you must convert this to atom like Elixir.HTTPoison. It is ugly, but I think this works fine. What things will not work this way and must be set in a config file for compile time config?
Thank you for your replies!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 15 to 6- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
dch
The
Application.envis 100% ets:You can look in the observer app, if you select
view -> ETS tables -> system tablestoo.For better (read-only) performance, look at persistent_term — OTP 29.0.2 (erts 17.0.2) the persistent term cache, added in OTP21.2. Note that updating this is a java-esque stop-the-world scenario for the entire VM.
hauleth
It is more like reading from ETS AFAIK. That is why it is not the best performance-wise when used in environment that need to be as fast as possible (like
loggercalls).You cannot do stuff like:
In your
config/config.exsnor inconfig/runtime.exsas when these files are evaluated by Mixkernelapplication is already started and running. This mean that you cannot easily configureloggerin development that will work from the beginning of the VM lifetime (like for example SASL startup messages).Let just say, that this isn’t very popular approach in Elixir development to use Erlang’s
loggerto full extent, but with Elixir 1.11 it can became more and more feasible to do so, as Elixir backends do not have simple access to structured logging (it will always be translated to plain string) nor to all log levels (these have access to “basics” -debug/info/warn/error, while Elixir 1.11 supports all 7 syslog levels). There are PRs to OTP to improve that, but it will take some time before that functionality will be available in Elixir.vrod
Interesting, thank you! I am wondering can you clarify somethings?
Is
Application.get_env/3reading from the process state?How is configuration of Erlang’s
loggerPITA? (I am only familiar with basic log level setting)hauleth
There are basic 2 types of config in Elixir code:
Application.get_env/{2,3}in any part of the code, even compile time, so people often did stuff like: This caused the@optionto be set during compilation, so if someone was using releases (Distillery or Relx at the time) could be confused why@optiondidn’t changed when the configuration was changed on the target server. Since 1.10 we haveApplication.compile_env/{2,3}andApplication.get_env/{2,3}will print warning when used in compile time. There are few examples of applications that use compile time env and in few situations this still sometimes makes some sense (for example poor-man dependency injection).Application.get_env/{2,3}calls within functions body, that is it. The “funny” thing there is that runtime configuration is also divided in 2 separate things (and people often forgot about it):Applicationbehaviour, or ininit/1functions of the servers). This is for example reason why simpleApplication.put_env(:logger, :level, :warning)will not work, and you need to useLogger.configure(level: :warning)or reason why you cannot configure:kerneland:stdlibapplications viaconfig/config.exs(so for example configuration of Erlang’sloggeris currently enormous PITA in Elixir).Application.get_env/{2,3}is called “in-place”, where it is needed. Reason why a lot components cannot be configured that way are mainly 2:So
1.is obviously something that you cannot configure in runtime (examples of such behaviour is:mimedatabase). And depending when yourVaporconfiguration will be ran1.1.can also be off limits, at least for some applications (notably:kerneland:stdlibare hard to configure with any Elixir tooling).vrod
Wow this really made me think. Thank you for this strategy! I tried it and it works very well – the
hexsuggestion was helpful for study.vrod
This is a beautiful little package! Thank you for sharing your approach – it works well!
Nicd
This suffers from being long and containing
ifs, but I’m posting it anyway for reference. I went 100% onruntime.exsin my project and only have a couple of things that need to be set at compile time in theconfig.exs..envwhen developing locallyThis has worked well for me. Even though the runtime config file is big, it’s not really that big once you get to know it, and I can have unified config for both development and release time (just using
.envin development for convenience).RudManusachi
What about having in
config/test.exsand in
config/runtime.exs[/quote]
For me if-statement is smell almost everywhere but configs
Take a look at the example how configs are organized in hexpm/config at main · hexpm/hexpm · GitHub
vrod
Forgive me for my struggle to understand a good solution. I think my options are to do maybe these:
Option 1: fill
runtime.exs:Pro: declarative, clear
Con: double long runtime.exs. Also if-statements in configs are always for me a smell.
Option 2: use test_helper.exs
Use simple
runtime.exsand add test values totest_helper.exslike maybe this:and then in
test_helper.exsI can doneApplication.put_envlikePro: simple
runtime.exs(no double, no if-statement)Con: cannot enforce System ENV vars using
System.fetch_env!– only get_env would work so that execution does not stop beforetest_helper.exsruns and a value is supplied.Option 3: Vapor
I looked also at Vapor. I like this: it could replace
runtime.exs100% I think. But it is still a problem when you must manually take a value and useApplication.put_envto put it into the correct place so your app and deps can find it. For example, imagine a dependency with config like this:With vapor, I can get
THING2ENV var from.envbut I must be careful with any deep config like this example dependancy. Where to put it once I have it? I think I must merge map and then put inside carefully into Application process dictionary.Pro: support for
.envand.env.{ENV}files for each override. Errors when config is not correct.Con: difficult for complex config that rely on
Application.get_env.I think there must be other ways. Sorry for my confusion. I admit I thought this was a easy topic but I am understanding more that config has subtle!
lud
You can use Application.put_env in your tests directly.