keep a circular buffer of errors cached in memory
diff --git a/src/rexi.erl b/src/rexi.erl
index 0ba77bd..9d34c51 100644
--- a/src/rexi.erl
+++ b/src/rexi.erl
@@ -44,7 +44,7 @@
-spec cast(node(), pid(), {atom(), atom(), list()}) -> reference().
cast(Node, Caller, MFA) ->
Ref = make_ref(),
- ok = gen_server:cast({?SERVER, Node}, {doit, {Caller,Ref}, MFA}),
+ ok = gen_server:cast({?SERVER, Node}, {doit, {Caller,Ref}, get(nonce), MFA}),
Ref.
%% @doc Sends an async kill signal to the remote process associated with Ref.
diff --git a/src/rexi_server.erl b/src/rexi_server.erl
index b5db9ec..2161099 100644
--- a/src/rexi_server.erl
+++ b/src/rexi_server.erl
@@ -15,14 +15,18 @@
-module(rexi_server).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
- code_change/3]).
+ code_change/3, calls/1, set_call_buffer_size/1]).
--export([start_link/0, init_p/2]).
+-export([start_link/0, init_p/3]).
-include_lib("eunit/include/eunit.hrl").
-record(st, {
- workers = ets:new(workers, [private, {keypos,2}])
+ workers = ets:new(workers, [private, {keypos,2}]),
+ err_cache = queue:new(),
+ err_cache_max = 20,
+ err_cache_len = 0
+
}).
start_link() ->
@@ -31,13 +35,40 @@
init([]) ->
{ok, #st{}}.
+calls(N) ->
+ {ok, gen_server:call(?MODULE,{calls, N},infinity)}.
+
+set_call_buffer_size(N) ->
+ {ok, gen_server:call(?MODULE,{cache_max, N},infinity)}.
+
+handle_call({calls, N}, _From, #st{err_cache=Q}=St) ->
+ ErrList = lists:sublist(lists:reverse(queue:to_list(Q)),1,N),
+ {reply,ErrList,St};
+
+handle_call({cache_max, N}, _From, #st{err_cache_len=Len,
+ err_cache_max=Max, err_cache=Q}=St) ->
+ {NewQ,NewLen} = case N < Len of
+ true ->
+ List = queue:to_list(Q),
+ {queue:from_list(lists:sublist(List,(Len-N)+1,Len)),
+ N};
+ false ->
+ {Q,Len}
+ end,
+ {reply, Max, St#st{err_cache_max=N, err_cache_len=NewLen, err_cache=NewQ}};
handle_call(_Request, _From, St) ->
{reply, ignored, St}.
+
handle_cast({doit, From, MFA}, #st{workers=Workers} = St) ->
- {LocalPid, Ref} = spawn_monitor(?MODULE, init_p, [From, MFA]),
+ {LocalPid, Ref} = spawn_monitor(?MODULE, init_p, [From, MFA, ""]),
{noreply, St#st{workers = add_worker({LocalPid, Ref, From}, Workers)}};
+handle_cast({doit, From, Nonce, MFA}, #st{workers=Workers} = St) ->
+ {LocalPid, Ref} = spawn_monitor(?MODULE, init_p, [From, MFA, Nonce]),
+ {noreply, St#st{workers = add_worker({LocalPid, Ref, From}, Workers)}};
+
+
handle_cast({kill, FromRef}, #st{workers=Workers} = St) ->
case find_worker_from(FromRef, Workers) of
{Pid, KeyRef, {_, FromRef}} ->
@@ -51,11 +82,28 @@
handle_info({'DOWN', Ref, process, _, normal}, #st{workers=Workers} = St) ->
{noreply, St#st{workers = remove_worker(Ref, Workers)}};
-handle_info({'DOWN', Ref, process, Pid, Reason}, #st{workers=Workers} = St) ->
+handle_info({'DOWN', Ref, process, Pid, Reason}, #st{workers=Workers,
+ err_cache=Q,
+ err_cache_max=Max,
+ err_cache_len=Len} = St) ->
case find_worker(Ref, Workers) of
{Pid, Ref, From} ->
- notify_caller(From, Reason),
- {noreply, St#st{workers = remove_worker(Ref, Workers)}};
+
+ {Error,{M,F,A},Nonce,Stack} = Reason,
+
+ {NewQ,NewLen} =
+ case Len >= Max of
+ true ->
+ Q1 = queue:drop(Q),
+ {Q1,Len};
+ _ ->
+ {Q,Len+1}
+ end,
+ NewQ1 = queue:in([now(),From,Nonce,M,F,A],NewQ),
+ notify_caller(From, {Error,Stack}),
+ {noreply, St#st{workers = remove_worker(Ref, Workers),
+ err_cache=NewQ1,
+ err_cache_len=NewLen}};
false ->
{noreply, St}
end;
@@ -71,14 +119,14 @@
{ok, St}.
%% @doc initializes a process started by rexi_server.
--spec init_p({pid(), reference()}, {atom(), atom(), list()}) -> any().
-init_p(From, {M,F,A}) ->
+-spec init_p({pid(), reference()}, {atom(), atom(), list()}, string()) -> any().
+init_p(From, {M,F,A}, Nonce) ->
put(rexi_from, From),
put(initial_call, {M,F,length(A)}),
try apply(M, F, A) catch exit:normal -> ok; Class:Reason ->
Stack = clean_stack(),
- error_logger:error_report([{?MODULE, {Class, Reason}}, Stack]),
- exit({Reason, Stack})
+ error_logger:error_report([{?MODULE, Nonce, {Class, Reason}}, Stack]),
+ exit({Reason,{M,F,A},Nonce,Stack})
end.
%% internal