Author: dreiss
Date: Thu Jun 4 02:01:32 2009
New Revision: 781636
URL: http://svn.apache.org/viewvc?rev=781636&view=rev
Log:
THRIFT-211. erlang: Support "tethered" clients
Add a client option that causes clients to monitor their creators
and terminate when the creator dies. This makes it possible to
prevent client leaks without linking, because the latter causes
application code to be killed when a transport error occurs and
exits are not trapped.
Modified:
incubator/thrift/trunk/lib/erl/src/thrift_client.erl
incubator/thrift/trunk/test/erl/src/test_tether.erl
Modified: incubator/thrift/trunk/lib/erl/src/thrift_client.erl
URL:
http://svn.apache.org/viewvc/incubator/thrift/trunk/lib/erl/src/thrift_client.erl?rev=781636&r1=781635&r2=781636&view=diff
==============================================================================
--- incubator/thrift/trunk/lib/erl/src/thrift_client.erl (original)
+++ incubator/thrift/trunk/lib/erl/src/thrift_client.erl Thu Jun 4 02:01:32
2009
@@ -101,12 +101,14 @@
%% ProtocolFactory :: fun() -> thrift_protocol()
start(ProtocolFactory, Service, ClientOpts)
when is_function(ProtocolFactory), is_atom(Service) ->
- Starter =
+ {Starter, Opts} =
case lists:keysearch(monitor, 1, ClientOpts) of
{value, {monitor, link}} ->
- start_link;
+ {start_link, []};
+ {value, {monitor, tether}} ->
+ {start, [{tether, self()}]};
_ ->
- start
+ {start, []}
end,
Connect =
@@ -119,7 +121,7 @@
end,
- Started = gen_server:Starter(?MODULE, [Service], []),
+ Started = gen_server:Starter(?MODULE, [Service, Opts], []),
if
Connect ->
@@ -171,7 +173,13 @@
%% {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
-init([Service]) ->
+init([Service, Opts]) ->
+ case lists:keysearch(tether, 1, Opts) of
+ {value, {tether, Pid}} ->
+ erlang:monitor(process, Pid);
+ _Else ->
+ ok
+ end,
{ok, #state{service = Service}}.
%%--------------------------------------------------------------------
@@ -262,6 +270,11 @@
%% {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
+handle_info({'DOWN', MonitorRef, process, Pid, _Info}, State)
+ when is_reference(MonitorRef), is_pid(Pid) ->
+ %% We don't actually verify the correctness of the DOWN message.
+ {stop, parent_died, State};
+
handle_info(_Info, State) ->
{noreply, State}.
Modified: incubator/thrift/trunk/test/erl/src/test_tether.erl
URL:
http://svn.apache.org/viewvc/incubator/thrift/trunk/test/erl/src/test_tether.erl?rev=781636&r1=781635&r2=781636&view=diff
==============================================================================
--- incubator/thrift/trunk/test/erl/src/test_tether.erl (original)
+++ incubator/thrift/trunk/test/erl/src/test_tether.erl Thu Jun 4 02:01:32 2009
@@ -27,7 +27,16 @@
io:format("PASS. Linked owner is dead.~n")
end,
- check_extras(2),
+ Pid3 = erlang:spawn(?MODULE, test_tethered, []),
+ receive after 200 -> ok end, % Wait for completion.
+ case is_up(Pid3) of
+ true ->
+ io:format("PASS. Tethered owner still alive.~n");
+ false ->
+ io:format("FAIL. Tethered owner is dead.~n")
+ end,
+
+ check_extras(3),
erlang:halt().
@@ -54,7 +63,11 @@
{linked, true} ->
io:format("FAIL. Linked client still alive.~n");
{linked, false} ->
- io:format("PASS. Linked client dead.~n")
+ io:format("PASS. Linked client dead.~n");
+ {tethered, true} ->
+ io:format("FAIL. Tethered client still alive.~n");
+ {tethered, false} ->
+ io:format("PASS. Tethered client dead.~n")
end,
check_extras(N-1)
after
@@ -115,3 +128,23 @@
%% Exit abnormally to kill our linked extra client.
%% But we should never get here.
exit(die).
+
+test_tethered() ->
+ {ok, Client1} = make_thrift_client([{connect, false}, {monitor, tether}]),
+ tester ! {client, tethered, Client1},
+ {ok, Client2} = make_thrift_client([{connect, false}, {monitor, tether}]),
+ io:format("PASS. Tethered clients created.~n"),
+ try
+ gen_server:call(Client2, {connect, make_protocol_factory(2)}),
+ io:format("FAIL. Tethered client connected.~n", [])
+ catch
+ Kind:Info ->
+ io:format("PASS. Caught tethered error. ~p:~p~n", [Kind, Info])
+ end,
+ receive after 100 ->
+ io:format("PASS. Still alive after tethered death.~n"),
+ % Hang around a little longer so our parent can verify.
+ receive after 200 -> ok end
+ end,
+ %% Exit abnormally to kill our tethered extra client.
+ exit(die).