From 982c72de7b412c95de1878d0ab8b859977188ff0 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Tue, 10 Jun 2008 22:58:33 +0000 Subject: [PATCH] Properly handle exceptions git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@666384 13f79535-47bb-0310-9956-ffa450edef68 --- .../cpp/src/generate/t_alterl_generator.cc | 5 +- lib/alterl/src/thrift_processor.erl | 79 +++++++++++++++++-- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/compiler/cpp/src/generate/t_alterl_generator.cc b/compiler/cpp/src/generate/t_alterl_generator.cc index 9f753874..cb4c1af0 100644 --- a/compiler/cpp/src/generate/t_alterl_generator.cc +++ b/compiler/cpp/src/generate/t_alterl_generator.cc @@ -535,10 +535,7 @@ void t_alterl_generator::generate_function_info(t_service* tservice, 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): diff --git a/lib/alterl/src/thrift_processor.erl b/lib/alterl/src/thrift_processor.erl index 14724aa7..217c2161 100644 --- a/lib/alterl/src/thrift_processor.erl +++ b/lib/alterl/src/thrift_processor.erl @@ -46,29 +46,92 @@ handle_function(State = #state{in_protocol = IProto, {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}. -- 2.17.1