[erlang-questions] Use of application environment

Serge Aleynikov saleyn@REDACTED
Wed Dec 3 05:08:24 CET 2008

Note that there's already a config_change callback in the OTP 
application behavior that can be used as a notification mechanism.

This post illustrates a way to reload the application's configuration 
and trigger the config_change callback so that the application can 
perform dynamic reconfiguration without restarting:


This is a simplistic approach that doesn't involve configuration 
validation.  Actually this was a part of a configuration management 
framework that we developed at my former employer that included a 
configuration server that maintained the versioned configuration 
repository that also performed syntax verification based on the 
application's metadata deployed with each app that included all needed 
parameters for each environment type (e.g. prod/dev/qa/etc), parameter 
types, defaults, update actions (such as reload environment, restart 
application, restart node, etc.), parameter documentation.  The server 
would perform configuration validation based on this metadata and reject 
unconformable input.  Each node would run a configuration client that 
upon startup would query the configuration server and rebuild the local 
configuration file if there were any parameter changes.  It would then 
use that configuration file in starting a release.



Edwin Fine wrote:
> To everyone that responded this time round, thanks SO MUCH for your input.
> It all made sense. Contradictions in approaches that I saw only reflect
> different design decisions and tradeoffs; all approaches are valid.
> The approach I am thinking of is a bit ambitious, or maybe a bad idea, but
> here goes the background.
> In operating systems like Linux and Solaris, and certainly at one point this
> was true, there are parameters that can be changed dynamically, and those
> which require a restart of the operating system. In the early days, many
> parameter changes required a kernel recompile, although I imagine there are
> much fewer of those today. I am old enough to remember vaguely the joys
> (not) of VAX/VMS AUTOGEN and SYSGEN.
> Moving on to something like WebLogic, it has parameters that you can change
> via its admin server. Some parameter changes are reflected immediately in
> the run-time environemnt, others require a restart of the application
> server.
> It is reasonable to say, therefore, that there are two main categories of
> parameters: static and dynamic. Changes to static parameters will often
> require some thing(s) in the application tree to be killed so they can
> reload their state (and hence get the changed parameters). Alternatively, I
> suppose one could use the OTP facilities to do a code_change, but I have
> zero knowledge or experience of this, so I won't comment further, other than
> to say that my understanding of this is that some Erlang/OTP users prefer to
> just restart the application (if their circumstances/SLA allow it) and avoid
> the reported complexities.
> My concern is with dynamic parameters. Static parameters can be changed in
> the config file, either via something like Erlware's GAS application or
> using a trusty editor.
> As for dynamic parameters, I am not a fan of polling for changes. I prefer
> event-driven approaches. My approach for this is as follows:
>    - Have a config server that loads all parameters from the application
>    environment (so far, like GAS);
>    - All workers that wish to be notified of config changes subscribe to a
>    set of events with the registered config server (observer pattern). It's
>    possible and probably desirable that the config server could monitor
>    subscribing processes and remove them from the subscription list if they
>    exit.
>    - These workers implement handle_info clauses that detect an incoming
>    event, say, {config_event, {evt_change, proplist()}}.
>    - Dynamic changes are made by using the interface to the config server
>    (or maybe changing the sys.config file - see later for discussion). Whenever
>    something changes, the config server sends to the appropriate subscribers
>    messages that contain subscriber-specific changes.
>    - When a subscriber gets the message, it changes its configuration (e.g.
>    its #state{} record) if needed and takes appropriate actions in response to
>    the changed value(s).
>    - The config server could have an API call to persist the configuration
>    back to the original config file.
> There are challenges inherent in such a design.
>    - *What happens if the config server crashes?* All the dynamic changes
>    are lost, as is knowledge of the processes which had earlier subscribed.
>       - One possibility could be to persist the config server's state, and
>       when reloading it check to see if there's a crash state, load the latest
>       application environment settings, and merge the crash state into that.
>       Thereafter one could check to see if the processes are still alive and
>       remove them from the subscription list. This seems very messy and error
>       prone.
>       - Another possibility could be to link to (rather than monitor) the
>       subscribing processes. If the config server goes down, the
> subscribers will
>       receive an EXIT signal and can then periodically try to resubscribe. This
>       unfortunately means that all subscribers have to handle that EXIT signal.
>    - *When changes are made to a config value using the API of the config
>    server, how does one ensure that the new value has the correct data
>    structure?* For example, if the value was originally stored in the config
>    file as an integer(), and someone changes the value via the API to a list,
>    this may crash a server.
>       - This suggests that the config server has to know the type of data
>       stored. How does it do that? I suppose it could test that the new value
>       coming in is the same type as the existing one. But my (limited)
>       understanding of Erlang is that there's no way to write T = type_of(Var),
>       only a set of tests, such as is_integer(), is_list() , and so
> on, which is
>       cumbersome to use to test types. But it could be done for simple
> types. And
>       if the type is a complex (i.e. composite one), such as a list of
> terms, how
>       does one ensure that the structure is not wrongly changed? Now one has to
>       write some sort of schema definition language and schema
> validator. Unless
>       there is an easier way? I suppose one could ban any non-simple
> configuration
>       values, but that's not acceptable.
>       - One could mandate that changes are only allowed to the standard
>       Erlang config file, which the config server picks up (as in GAS). This,
>       however, does not guarantee that the Erlang config file is even
>       syntactically correct, let alone that the values therein have the correct
>       representation.
>       - Which brings me to this: *Has anyone ever written an Erlang config
>       file validator* (other than Erlang itself, I mean)? I would really
>       like something that allows me to validate a config file - both
> syntactically
>       and schema - before putting it in place. The errors that occur due to a
>       syntactically incorrect config file are often hard to find (for
> me, anyway).
>       Again, to do this correctly implies the need for a config file schema
>       language and a schema validator.
> That was longer than I expected. If you made it this far, you are either
> very interested, very bored, or very determined :)
> Any thoughts on this matter? Who knows, maybe someone has already done this
> (unsure if GAS does all this) and it's on some Open Source repository
> somewhere. I did search, but I might have missed it.
> Regards,
> Edwin Fine
>> On 11/24/08 9:27 PM, "Edwin Fine" <erlang-questions_efine@REDACTED> wrote:
>> Hi all,
>> Is it considered bad practice to use application environment variables
>> (i.e. application:get_env/2,3) in workers, as opposed to only passing config
>> information via the start()/init() calls? I am finding it tedious as I add
>> more configuration data to the sys.config file, to get_env() the data in a
>> supervisor and then parcel it out to the workers. Also, it becomes a pain to
>> change the values at runtime, whereas if I put a function like this in an
>> affected worker
>> my_foo_val() ->
>>     application:get_env(my_app, my_foo_val, ?SOME_SANE_DEFAULT).
>> then runtime changes can be made immediately using set_env(), and it
>> becomes much easier to add new config data, but I feel uneasy, almost as if
>> I'm using global variables. From a load point of view, I only do this in
>> places where the value is not used at a high rate.
>> What is the preferred or recommended (or even most common) practice?
>> Regards,
>> Edwin Fine
>> ------------------------------
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://www.erlang.org/mailman/listinfo/erlang-questions
> ------------------------------------------------------------------------
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://www.erlang.org/mailman/listinfo/erlang-questions

More information about the erlang-questions mailing list