[erlang-questions] Best practices for handling invalid / unexpected messages

Ahmed Omar spawn.think@REDACTED
Fri May 13 21:57:39 CEST 2011


Hello Ciprian,

IMHO
A) Define the "Caller" :
 i believe you need to make a distinction between the boundaries of your
system and the internals.

- On the boundaries, when other systems can feed data into yours, it's
better to "validate" the inputs.
- Introduce client APIs for your gen_server, wrapping/abstracting the actual
gen_server:call
- Do the validation in these APIs, so the crash will be in the client
process scope.

For the gen_server callbacks itself (handle_call, handle_cast, handle_info),
i would vote for letting it crash if something wrong got there, because
1) Makes your code cleaner, more neat and easier to debug
2) Doesn't hide bugs (Why a wrong request was made, and why it was not
validated on the boundaries, also if the caller doesn't check replies,
..etc)

B) Other dependent processes :
It depends on your design, services provided by that gen_server and kind of
state it keeps. In some cases, the processes needs to be restarted along
with it (maybe to do initializations all over again), in other cases they
don't need that. Define your case, and put the supervision tree that suites
your needs.

I hope this helps

On Fri, May 13, 2011 at 8:46 PM, Ciprian Dorin Craciun <
ciprian.craciun@REDACTED> wrote:

>    Hello all!
>
>    Lately I've started programming a bit more seriously in Erlang,
> and after creating a few `gen_server` or `gen_fsm` components, I've
> started wondering what is the best way to handle unexpected or invalid
> requests / messages. (For example in `handle_call`, or `handle_info`
> or state handlers.) (By invalid requests I mean those that have the
> correct form (i.e. a tuple `{add, A, B}`) but invalid syntax (i.e. `A`
> is an atom); by unexpected messages I mean those that fail to even
> loosely match a valid pattern (i.e. `{some_unrecognized_operation, A,
> B}`.)
>
>    I think of three possibilities:
>    * reply back with an error:
> ~~~~
> handle_call (Request, _Sender, State) -> {reply, {error,
> {invalid_request, Request}}, State}.
> ~~~~
>    * exit with an error;
> ~~~~
> handle_call (Request, _Sender, State) -> {stop, {error,
> {invalid_request, Request}}, State}.
> ~~~~
>    * don't even create a special catch-all case and just let the
> process fail with `function_clause` error;
>
>    Now each of these have advantages or disadvantages:
>    * the first one is "polite" to the caller, letting him retry, but
> could lead to hidden bugs if the caller doesn't check the return term;
>    * the second one I think fits more the Erlang philosophy of
> "let-it-crash", but could lead to state loss (i.e. an ETS table);
>    * the last one I consider to be just rude as it doesn't give any
> information on why it failed;
>
>    Furthermore, let's say a process depends in his operation on
> another process, should it link the dependency process, should it
> monitor, or should it just fail on call?
>
>    So I ask the other Erlang developers how do they handle these
> situations?
>
>    Thanks,
>    Ciprian.
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions
>



-- 
Best Regards,
- Ahmed Omar
http://nl.linkedin.com/in/adiaa
Follow me on twitter
@spawn_think <http://twitter.com/#!/spawn_think>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20110513/4f8d3ed9/attachment.htm>


More information about the erlang-questions mailing list