[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