Author: dreiss
Date: Tue Jun 10 15:58:33 2008
New Revision: 666384
URL: http://svn.apache.org/viewvc?rev=666384&view=rev
Log:
Properly handle exceptions
Modified:
incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc
incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl
Modified: incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc
URL:
http://svn.apache.org/viewvc/incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc?rev=666384&r1=666383&r2=666384&view=diff
==============================================================================
--- incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc
(original)
+++ incubator/thrift/trunk/compiler/cpp/src/generate/t_alterl_generator.cc Tue
Jun 10 15:58:33 2008
@@ -535,10 +535,7 @@
indent(f_service_) <<
"function_info(" << name_atom << ", exceptions) ->" << endl;
indent_up();
-
- // TODO(todd) exceptions here are probably broken
- indent(f_service_) << generate_type_term(xs, false) << ";" << endl;
-
+ indent(f_service_) << generate_type_term(xs, true) << ";" << endl;
indent_down();
// function_info(Function, is_async):
Modified: incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl
URL:
http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl?rev=666384&r1=666383&r2=666384&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl (original)
+++ incubator/thrift/trunk/lib/alterl/src/thrift_processor.erl Tue Jun 10
15:58:33 2008
@@ -46,29 +46,92 @@
{ok, Params} = thrift_protocol:read(IProto, InParams),
- {Micro, Result} = timer:tc(Handler, handle_function, [Function, Params]),
- error_logger:info_msg("Processed ~p(~p) in ~.4fms~n",
- [Function, Params, Micro/1000.0]),
-
+ try
+ {Micro, Result} = better_timer(Handler, handle_function, [Function,
Params]),
+ error_logger:info_msg("Processed ~p(~p) in ~.4fms~n",
+ [Function, Params, Micro/1000.0]),
+ handle_success(State, Function, Result)
+ catch
+ throw:Exception when is_tuple(Exception), size(Exception) > 0 ->
+ error_logger:warning_msg("~p threw exception: ~p~n", [Function,
Exception]),
+ handle_exception(State, Function, Exception),
+ ok % we still want to accept more requests from this client
+ end.
+
+handle_success(State = #state{out_protocol = OProto,
+ service = Service},
+ Function,
+ Result) ->
ReplyType = Service:function_info(Function, reply_type),
StructName = atom_to_list(Function) ++ "_result",
case Result of
{reply, ReplyData} ->
Reply = {{struct, [{0, ReplyType}]}, {StructName, ReplyData}},
- ok = send_reply(OProto, Function, Reply);
+ ok = send_reply(OProto, Function, ?tMessageType_REPLY, Reply);
ok when ReplyType == {struct, []} ->
- ok = send_reply(OProto, Function, {ReplyType, {StructName}})
+ ok = send_reply(OProto, Function, ?tMessageType_REPLY, {ReplyType,
{StructName}})
end,
ok.
+handle_exception(State = #state{out_protocol = OProto,
+ service = Service},
+ Function,
+ Exception) ->
+ ExceptionType = element(1, Exception),
+ % Fetch a structure like {struct, [{-2, {struct, {Module, Type}}},
+ % {-3, {struct, {Module, Type}}}]}
+
+ ReplySpec = Service:function_info(Function, exceptions),
+ {struct, XInfo} = ReplySpec,
+
+ true = is_list(XInfo),
+
+ % e.g.: [{-1, type0}, {-2, type1}, {-3, type2}]
+ XPairs = [{Fid, Type} || {Fid, {struct, {_Module, Type}}} <- XInfo],
+
+ Mapper = fun({Fid, Type}) ->
+ case Type of
+ ExceptionType ->
+ Exception;
+ _ ->
+ undefined
+ end
+ end,
+ % Assuming we had a type1 exception, we get: [undefined, Exception,
undefined]
+ ExceptionList = lists:map(Mapper, XPairs),
+ ExceptionTuple = list_to_tuple([Function | ExceptionList]),
+
+ % Make sure we got at least one defined
+ case lists:all(fun(X) -> X =:= undefined end, ExceptionList) of
+ true ->
+ ok = handle_unknown_exception(State, Function, Exception);
+ false ->
+ ok = send_reply(OProto, Function, ?tMessageType_REPLY, {ReplySpec,
ExceptionTuple})
+ end.
+
+handle_unknown_exception(State, Function, Exception) ->
+ io:format("Unknown exception!~n"),
+ ok.
+
-send_reply(OProto, Function, Reply) ->
+send_reply(OProto, Function, ReplyMessageType, Reply) ->
ok = thrift_protocol:write(OProto, #protocol_message_begin{
name = atom_to_list(Function),
- type = ?tMessageType_REPLY,
+ type = ReplyMessageType,
seqid = 0}),
ok = thrift_protocol:write(OProto, Reply),
ok = thrift_protocol:write(OProto, message_end),
ok.
+
+
+%%
+% This is the same as timer:tc except that timer:tc appears to catch
+% exceptions when it shouldn't!
+%%
+better_timer(Module, Function, Args) ->
+ T1 = erlang:now(),
+ Result = apply(Module, Function, Args),
+ T2 = erlang:now(),
+ {timer:now_diff(T2, T1), Result}.