On Sat, Aug 9, 2008 at 7:45 AM, Claes Wikstrom <klacke@tail-f.com> wrote:
Edwin Fine wrote:

Thanks so much for replying with so much detail. I hear what you are saying about documentation.

I'm not sure I understand your dislike of the proplist-style interface. Ok, it's maybe more cumbersome than setting record variables directly, but It's used extensively in OTP and is almost a standard idiom, and it's much cleaner than having to fiddle with things like setting the Yaws gconf flags. Honestly, which of these code snippets is more readable, and easier to do in a run-time (embedded) configuration?

As I wrote, a proplist would work fine for the gconf{} part
e.g. settings that effect the entire server. However proplists
doesn't work at all for the [[#sconf{}]...] part.
It would be cumbersome indeed ... although possible to express
that as proplists.
Ok, I hear you.

I don't know, maybe it's just my relative lack of Erlang experience talking here.

Don't know about that - I like proplists too.

I didn't want to start Yaws as a separate application when it's really embedded inside /my/ application. It also just didn't feel right, somehow, to have a Web server running on the default port and a default document root until it is reconfigured correctly, even if it is just for a short while.

If yaws is started in embedded mode, it runs but binds no
ports whatsoever until it's fed a config through yaws_api:setconf/2

Ok, I understand. I must have gotten got the wrong impression, because I started what I thought was an embedded Yaws and was able to bind to it on port 8080 before calling setconf. It must have been started in non-embedded mode.

The way I eventually embedded Yaws was to create a one-for-all supervisor between my top-level supervisor and the Yaws supervisor. This has two child processes; one is obviously the Yaws supervisor, and the other is a gen_server whose only purpose is to receive the Yaws-specific application parameters from its supervisor, and call yaws_api:setconf() with them. It probably seems like an overkill to use a gen_server for this, but my understanding of the OTP supervisor documentation is that a supervisor may only have as child processes other supervisors or OTP-compliant processes, and a gen_server was for me the easiest and least error-prone choice.


The idea behind this organization is that if the Yaws supervision tree dies for any reason, it will be restarted /and /reconfigured correctly every time. Out of interest, why not have optional parameters to the start() function in the Yaws supervisor that allows one to pass the same arguments as yaws_api:setconf? This would start Yaws in embedded mode, and I think solves problems such as having to set Yaws application environment variables and do a two-phase startup. What do you think of that idea? I'll take a look at it in the meantime and see if I can get it to work.

If there are better ways to do what I have described - other than application:start(yaws) + yaws_api:setconf() -  and there surely must be, I would certainly appreciate learning about them.

I kind of like the idea of

1. start empty
2. setconf

I like having that capability, but I don't like being forced to do it if I  just want a one-step start.

This also has the very nice capability of restarts. If your
app is reconfigured and subsequently hupped, all you need to
do to reconfigure yaws is to issue a new call to setconf
and yaws will figure out the diff between the two configs and
anly reconfigure (stop/start) servers that are effected.

Ah, I didn't know that (amongst many other things :). I didn't consider multiple servers because I don't use more than one in my app right now. That's a very nice feature. Still, I wouldn't know where to put the setconf call so that it's automatically issued if the Yaws supervisor tree dies, other than the way I've got it now. When you say "start empty", you mean start yaws_sup empty or application:start(yaws)?

If yaws:start() should take the config params, you'd have to
stop all www servers and the restart all. Not equally good.

Not necessarily. You could still call setconf and let it do its diff magic, couldn't you? As I see it, there are two use cases:
  1. The Yaws supervision tree dies, which it now (1.77) does if any of its child processes dies, in which case you config all the www servers through the "improved" yaws_sup:start().
  2. The Yaws supervision tree does not die, but you have to reconfigure, in which case you just call setconf the way you described.
Am I missing something?

Also - a sidenote on why I chose to use bitmasks in the
#gconf{} and the #sconf{} records. This is a memory optimization.
These records are passed around in quite a few calls to spawn()
and making such records smaller saves memory a lot.

I never had a problem with using bitmasks internally. As an old hand at 'C'/C++, I'm used to them and I understand the memory savings. It's just a bit of a pain to set a bunch of them individually, because Erlang variables are immutable and it seems to me like one has to jump through hoops (jump through loops, really) to set multiple bits sequentially, and use macros to avoid silly bit-twiddling mistakes. You only need to think of yaws_config to see my point.



For every expert there is an equal and opposite expert - Arthur C. Clarke