[erlang-questions] Use of application environment

Edwin Fine erlang-questions_efine@REDACTED
Tue Dec 2 23:29:19 CET 2008


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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20081202/82f2e799/attachment.htm>


More information about the erlang-questions mailing list