Confex already provides you a way to have a compile-time config and delegate resolution of it's part to runtime. This delegation is already very explicit even though it has a downside - values with :system tuples can have interference with values set by other libraries.
So what are we trying to solve:
Provide a way to separate compile and runtime configuration;
It should be as simple as possible and require developers to minimize changes to adopt them. People should not look into multiple files to figure out where some variable came from;
If it's not adopted, old way should keep working (probably issuing warnings);
Releases (we should have them though, but it's a separate work).
What we should not solve here:
Generalization of where runtime configuration lives (closer to code or in config files). Having it closer to code is always an option and if community thinks it's the way to go - it's more educational work rather than techical.
To further extend it:
We should not write to Application environment at all, instead, we can think of it as a compile-time configuration where system tuples are arbitrary values that tell us how to resolve their runtime value. (We would need to deprecate Confex.resolve_env!.)
Users do not always expect performance hit added by Confex callbacks that resolve the value each time it's called, a new cache layer should be added that resolves them only once and stored in a public ETS table (similar to how Application env work). It can be placed in Confex.RuntimeEnv module, which mimics Application.*_env behaviour. We may add a function to populate the app when it's started though.
Because configuration can change at runtime we should though how that caching works:
When Application env is changed (somebody can write a new :system elsewhere);
When new code is released (hot code upgrade);
When the value in external API is changed (probably we need a watch/2 optional callback for Confex adapters).
There are some edge cases when configuration change should trigger other action in the application, the best example I come up if Vault that rotates PostgreSQL password. So when password value is changed, there should be a code that subscribed to that change and gracefully restarts the connection pool.
Prepare showcase (probably with macros similar to Mix.Config) how it would work altogether.
This can be merged with some ideas from Jose RFC:
config_paths to get rid off import_config/1;
Application.Config can hold the macroses and Application[.Runtime] can become this runtime config "caching" layer;
Some more points from discussion and my own experience:
apps in umbrella should not have their own configuration by default, even though it should be possible to do if people want to cut off multiple releases from a single app.
Confex already provides you a way to have a compile-time config and delegate resolution of it's part to runtime. This delegation is already very explicit even though it has a downside - values with
:system
tuples can have interference with values set by other libraries.So what are we trying to solve:
What we should not solve here:
To further extend it:
We should not write to Application environment at all, instead, we can think of it as a compile-time configuration where system tuples are arbitrary values that tell us how to resolve their runtime value. (We would need to deprecate
Confex.resolve_env!
.)Users do not always expect performance hit added by Confex callbacks that resolve the value each time it's called, a new cache layer should be added that resolves them only once and stored in a public ETS table (similar to how Application env work). It can be placed in
Confex.RuntimeEnv
module, which mimicsApplication.*_env
behaviour. We may add a function to populate the app when it's started though.Because configuration can change at runtime we should though how that caching works:
:system
elsewhere);watch/2
optional callback for Confex adapters).There are some edge cases when configuration change should trigger other action in the application, the best example I come up if Vault that rotates PostgreSQL password. So when password value is changed, there should be a code that subscribed to that change and gracefully restarts the connection pool.
Prepare showcase (probably with macros similar to Mix.Config) how it would work altogether.
This can be merged with some ideas from Jose RFC:
config_paths
to get rid offimport_config/1
;Application.Config
can hold the macroses andApplication[.Runtime]
can become this runtime config "caching" layer;Some more points from discussion and my own experience:
Link to the discussion: https://elixirforum.com/t/proposal-moving-towards-discoverable-config-files/14302/73