Erlang错误处理哲学 - 案例与投掷

Phi*_*sky 6 error-handling erlang exception-handling

我正在Erlang中编写REST服务,需要先验证接收到的数据,然后再将其传递给其他内部函数进行进一步处理; 为了做到这一点,我目前正在使用这样的嵌套case表达式:

case all_args_defined(Args) of
    true ->
        ActionSuccess = action(Args),

        case ActionSuccess of
            {ok, _} -> ...;
            {fail, reason} -> {fail, reason}
        end,
    _ ->
        {fail, "args not defined"}
end,
...
Run Code Online (Sandbox Code Playgroud)

我意识到这有点难看,但这样我可以提供详细的错误信息.另外,我不认为通常的make it crash理念在这里适用 - 我不希望我的REST服务崩溃并且每当有人抛出无效参数时重新启动它.

但是,我正在考虑放弃所有那些cases支持伞形try/catch块来捕捉任何badmatch错误的人 - 这会有用吗?

fun() ->
    true = all_args_defined(Args),
    {ok, _} = action(Args).

%% somewhere else
catch fun().
Run Code Online (Sandbox Code Playgroud)

Ric*_*rdC 6

由于您要实现的是错误报告,因此您应该围绕执行操作和报告结果来构建事物.也许是这样的:


  execute(Action, Args) ->
    try
      check_args(Args),
      Result = action(Action, Args),
      send_result(Result)
    catch
      throw:{fail, Reason} ->
        report_error(Reason);
      ExceptionClass:Term ->
        %% catch-all for all other unexpected exceptions
        Trace = erlang:get_stacktrace(),
        report_error({crash, ExceptionClass, Term, Trace})
    end.

  %% all of these throw {fail, Reason} if they detect something fishy
  %% and otherwise they return some value as result (or just crash)
  action(foo, [X1, X2]) -> ...;
  action(foo, Args) -> throw({fail, {bad_arity, foo, 2, Args}});
  action(...) -> ...

  %% this handles the formatting of all possible errors 
  report_error({bad_arity, Action, Arity, Args}) ->
    send_error(io_lib:format("wrong number of arguments for ~w: "
                             "expected ~w, but got ~w",
                             [Action, Arity, length(Args)]));
  report_error(...) -> ...;
  report_error({crash, Class, Term, Trace}) ->
    send_error(io_lib:format("internal error: "
                             "~w:~w~nstacktrace:~n~p~n",
                             [Class, Term, Trace])).
Run Code Online (Sandbox Code Playgroud)