On Fri, May 13, 2011 at 10:19 PM, Ciprian Dorin Craciun <span dir="ltr"><<a href="mailto:ciprian.craciun@gmail.com">ciprian.craciun@gmail.com</a>></span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Fri, May 13, 2011 at 22:57, Ahmed Omar <<a href="mailto:spawn.think@gmail.com">spawn.think@gmail.com</a>> wrote:<br>
> Hello Ciprian,<br>
> IMHO<br>
> A) Define the "Caller" :<br>
>  i believe you need to make a distinction between the boundaries of your<br>
> system and the internals.<br>
> - On the boundaries, when other systems can feed data into yours, it's<br>
> better to "validate" the inputs.<br>
> - Introduce client APIs for your gen_server, wrapping/abstracting the actual<br>
> gen_server:call<br>
<br>
</div>    Indeed I wasn't to specific about the purpose of these processes.<br>
I was referring to the internal application processes, those which are<br>
shielded from the "real" callers through a module / process that<br>
exposes a REST interface or a RPC system where I try to validate the<br>
inputs and give back errors as you've described.<br>
<div class="im"><br>
<br>
> - Do the validation in these APIs, so the crash will be in the client<br>
> process scope.<br>
<br>
</div>    About the `gen_server:call` wrappers, should I really do any<br>
validation here if the exposed API is an "internal" one (as described<br>
above not directly exposed to the "network")? It could amount to a bit<br>
of overhead, especially if the validation is not a trivial one and<br>
involves the inspection of a deep structure?<br>
<div class="im"><br></div></blockquote><div><br></div><div>No. In case data is from inside your system, you might assume it's correct. (specially if validation will cause too much overhead).</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">
<br>
> For the gen_server callbacks itself (handle_call, handle_cast, handle_info),<br>
> i would vote for letting it crash if something wrong got there, because<br>
> 1) Makes your code cleaner, more neat and easier to debug<br>
> 2) Doesn't hide bugs (Why a wrong request was made, and why it was not<br>
> validated on the boundaries, also if the caller doesn't check replies,<br>
> ..etc)<br>
<br>
</div>    Ok.<br>
<div class="im"><br>
<br>
> B) Other dependent processes :<br>
> It depends on your design, services provided by that gen_server and kind of<br>
> state it keeps. In some cases, the processes needs to be restarted along<br>
> with it (maybe to do initializations all over again), in other cases they<br>
> don't need that. Define your case, and put the supervision tree that suites<br>
> your needs.<br>
<br>
</div>    Indeed a supervisor tree helps if both the dependent and<br>
dependency process are created by me and part of the same application.<br>
But if one process is provided by another application I can't resort<br>
anymore to `one_for_all` option, but instead I need to link the<br>
process. The only problem is that in this case the link is not quite<br>
bi-directional: i.e. if my dependency process fails then all the<br>
dependent processes should be restarted, but if only a dependent<br>
process fails, then the dependency could live on. Therefore I think<br>
monitors (inside the dependent process) could be a better solution,<br>
but working with monitors is not as easy as linking.<br>
<br>
<br></blockquote><div>Actually monitors are not that hard at all, you just need to understand them correctly. You still can use links and trap exit on your main process, but i personally don't prefer this way (only a preference)</div>
<div> I would recommend checking LYSE</div><div><a href="http://learnyousomeerlang.com/errors-and-processes">http://learnyousomeerlang.com/errors-and-processes</a> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">

> I hope this helps<br>
<br>
    Thanks for your reply, it confirmed / extended my initial hunches.<br>
<font color="#888888"><br>
    Ciprian.<br>
</font><div><div></div><div class="h5"><br>
<br>
> On Fri, May 13, 2011 at 8:46 PM, Ciprian Dorin Craciun<br>
> <<a href="mailto:ciprian.craciun@gmail.com">ciprian.craciun@gmail.com</a>> wrote:<br>
>><br>
>>    Hello all!<br>
>><br>
>>    Lately I've started programming a bit more seriously in Erlang,<br>
>> and after creating a few `gen_server` or `gen_fsm` components, I've<br>
>> started wondering what is the best way to handle unexpected or invalid<br>
>> requests / messages. (For example in `handle_call`, or `handle_info`<br>
>> or state handlers.) (By invalid requests I mean those that have the<br>
>> correct form (i.e. a tuple `{add, A, B}`) but invalid syntax (i.e. `A`<br>
>> is an atom); by unexpected messages I mean those that fail to even<br>
>> loosely match a valid pattern (i.e. `{some_unrecognized_operation, A,<br>
>> B}`.)<br>
>><br>
>>    I think of three possibilities:<br>
>>    * reply back with an error:<br>
>> ~~~~<br>
>> handle_call (Request, _Sender, State) -> {reply, {error,<br>
>> {invalid_request, Request}}, State}.<br>
>> ~~~~<br>
>>    * exit with an error;<br>
>> ~~~~<br>
>> handle_call (Request, _Sender, State) -> {stop, {error,<br>
>> {invalid_request, Request}}, State}.<br>
>> ~~~~<br>
>>    * don't even create a special catch-all case and just let the<br>
>> process fail with `function_clause` error;<br>
>><br>
>>    Now each of these have advantages or disadvantages:<br>
>>    * the first one is "polite" to the caller, letting him retry, but<br>
>> could lead to hidden bugs if the caller doesn't check the return term;<br>
>>    * the second one I think fits more the Erlang philosophy of<br>
>> "let-it-crash", but could lead to state loss (i.e. an ETS table);<br>
>>    * the last one I consider to be just rude as it doesn't give any<br>
>> information on why it failed;<br>
>><br>
>>    Furthermore, let's say a process depends in his operation on<br>
>> another process, should it link the dependency process, should it<br>
>> monitor, or should it just fail on call?<br>
>><br>
>>    So I ask the other Erlang developers how do they handle these<br>
>> situations?<br>
>><br>
>>    Thanks,<br>
>>    Ciprian.<br>
>> _______________________________________________<br>
>> erlang-questions mailing list<br>
>> <a href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a><br>
>> <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
><br>
><br>
><br>
> --<br>
> Best Regards,<br>
> - Ahmed Omar<br>
> <a href="http://nl.linkedin.com/in/adiaa" target="_blank">http://nl.linkedin.com/in/adiaa</a><br>
> Follow me on twitter<br>
> @spawn_think<br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br>Best Regards,<br>- Ahmed Omar<div><a href="http://nl.linkedin.com/in/adiaa" target="_blank">http://nl.linkedin.com/in/adiaa</a></div><div>Follow me on twitter</div>
<div><a href="http://twitter.com/#!/spawn_think" target="_blank">@spawn_think</a></div><br>