Erlang: does sys:get_status/1 interfere with timeout? - erlang

Say I have a gen_server process, P, which contains codes like this
handle_call(get_a, _From, #state{a = 1}=S) ->
Reply = S#state.a,
{reply, Reply, S, T=1000000};
If I do gen_server:call(P, get_a), then I would get a reply, namely 1, and if no message was sent to P in T after the gen call, then a timeout will occur.
If I do a sys:get_status(P) immediately after the gen call, would this cancel the timeout?

Calling sys:get_status/1,2 on your gen_server process does not cancel the timeout. And just for completeness, note that this is true whether or not your gen_server implements the optional format_status/2 callback.

Related

gen_server , a server can’t call its own API functions?

When I read Erlang OTP Action book, I found this reminder on page 117:
With your RPC server, you can try calling any function exported from any module available on the server side, except one: your own tr_server:get_count/0. In general, a server can’t call its own API functions. Suppose you make a synchronous call to the same server from within one of the callback functions: for example, if handle_info/2 tries to use the get_count/0 API function. It will then perform a gen_server:call(...) to itself. But that request will be queued up until after the current call to handle_info/2 has finished, resulting in a circular wait—the server is deadlocked.
But I looked at the tr_server sample code :
get_count() ->
gen_server:call(?SERVER, get_count).
stop() ->
gen_server:cast(?SERVER, stop).
handle_info({tcp, Socket, RawData}, State) ->
do_rpc(Socket, RawData),
RequestCount = State#state.request_count,
{noreply, State#state{request_count = RequestCount + 1}};
......
do_rpc(Socket, RawData) ->
try
{M, F, A} = split_out_mfa(RawData),
Result = apply(M, F, A), % tr_server process -> handle_info -> do_rpc ->call & cast
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Result]))
catch
_Class:Err ->
gen_tcp:send(Socket, io_lib:fwrite("~p~n", [Err]))
end.
I found the examples and cautions in the book inconsistent , the gen_server:call and gen_server:cast by tr_server process ownself.
Am I misinterpreting this?
Calling gen_server:cast from within the server process is fine, because it is asynchronous: it adds the message to the mailbox of the process and then continues, returning ok. Only gen_server:call has this problem, because it makes the process wait for an answer from itself.

gen_server not getting messages after httpc call

I have one process which sends a pause message to a gen_server like so:
Results = [gen_server:cast(Child, pause) ||
{Id, Child, _Type, _Modules} <- supervisor:which_children(?SERVER),
?IGNORE(Id) == false],
In my gen_server, I catch these messages in my handle_cast as follows:
handle_cast(pause, #state{task=#task{server=Serv,
service=Srv,
description=Desc}}=State) ->
lager:info("Suspending ~s, ~s, ~s.",[Serv, Srv, Desc]),
{noreply, State#state{suspended=true}};
handle_cast(Msg, State) ->
lager:error("Url Poller received unexpected cast message: ~p",[Msg]),
{noreply, State}.
What's really strange is that fairly frequently one of my gen_servers doesn't seem to receive the pause message -- I get no lager message and the process in question will not respond to subsequent attempts to pause (or resume).
Any ideas about what might be going on?
The gen_server is very simple, it uses erlang:send_after/3 to send itself a "poll" message. Upon receiving this poll message, if not paused, it hits a url and saves the response to an ETS and fires off another erlang:send_after/3 to poll again after an appropriate interval. If its paused, it simply fires off another erlang:send_after?3
All pause does is set the state to paused = true
Using observer, the stuck process shows that the current function is httpc:handle_answer and that the message queue is backing up
Sate Tab: Information "Timed out"
Tip "system messages are probably not treated by this process"
the top of the stack trace shows
httpc:handle_answer httpc.erl:636
I picked the code of httpc:handle_answer from github erlang otp inets http client:
(Note: it is not the same version as yours since the function goes from line 616 to 631)
handle_answer(RequestId, false, _) ->
{ok, RequestId};
handle_answer(RequestId, true, Options) ->
receive
{http, {RequestId, saved_to_file}} ->
?hcrt("received saved-to-file", [{request_id, RequestId}]),
{ok, saved_to_file};
{http, {RequestId, {_,_,_} = Result}} ->
?hcrt("received answer", [{request_id, RequestId},
{result, Result}]),
return_answer(Options, Result);
{http, {RequestId, {error, Reason}}} ->
?hcrt("received error", [{request_id, RequestId},
{reason, Reason}]),
{error, Reason}
end.
So the process is waiting for a message (coming after a call to httpc_manager:request(Request, profile_name(Profile) which has returned {ok, RequestId}), and this message does not come or it has a wrong format. Can you check the values of the parameters and the message queue?
headers which contained value other than string caused the httpc_handler exited. But after that, the caller hung at the 'receive' in httpc:handle_answer/3 forever since no message was sent to the caller.
you can test with this
Request1= {"http://www.google.com",[{"cookie",undefined}, {"test",123}],"application/x-www-form-urlencoded; charset=utf-8", <<"">>}.
httpc:request(post, Request1, [{timeout,1000}], []).

is a gen_server is up?

Is there a way to tell a gen_server: "supervisor has initialised all gen_servers, now you can send then messages"?
I have a worker gen_server whose job is to set up states of other gen_servers in his supervision tree. If I just start sending messages in init function of my configuration server, sometimes it gets {noproc, _}. I suppose that means that config server was to fast: he sent messages before supervisor had enough time to start all workers. I fixed that by putting timer:sleep(500) in config_server:init(), which ensures all gen_server had enough time to initialise, but this seems like a inelegant solution.
Is there a proper way to do this?
Return tuple with timeout 0 from init. Then immediately after it returns, handle_info(timeout, State) will be called. In handle_info make some call which won't return until the supervisor finishes initialization (e.g. supervisor:which_children).
info(PlayerId) ->
Pid = case global:whereis_name(util:getRegName({?MODULE, PlayerId})) of
P when is_pid(P) ->
P;
_ ->
{ok, P} = player_sup:start_child(PlayerId),
P
end,
gen_server:call(Pid, info).
This is my case to handle this issue. This worker process is triggered only when it is requested.
in function init() call gen_server:cast(init, State). message "init" will be first in message queue

Allowing a gen_fsm to timeout if it receives no messages

Normally if I'd like to have an Erlang process timeout I would use the following construct:
receive
Msg -> ok; %% handle message
after 60000 ->
%% Handle timeout and exit
end.
Is there a similar mechanism in the OTP servers such as gen_fsm? I will be spawning gen_fsm's for each active session with my application, and would like to have them exit if a timeout value for inactivity is exceeded after receiving a message.
I can write my own custom process if need be, but would prefer to use a gen_fsm if possible.
I dug some more and found the answer to my own question.
There is an optional fourth argument in message handler "Result"s that you can use which is a timeout.
so:
some_fsm_state({set, Val}, State) ->
NewState = do(Val, State),
{next_state, another_fsm_state, NewState, 5000};
another_fsm_state(timeout, State) ->
handle_timeout(State).
another_fsm_state({set, Val}, State) ->
%% more code that handles this state.
Once some_fsm_state is called, it transitions to the next state of "another_fsm_state" with a timeout of 5000ms. If not new message is received within 5000ms, then another_fsm_state(timeout, State) is called.
Clever OTP programmers. :)
It should be noted that this fourth element in the Results tuple can be hibernate. Please see Erlang documentation for more information.
Erlang - Hibernate
gen_fsm docs

What's the best way to do something periodically in Erlang?

I have a process that needs to do some work every fifteen seconds. I'm currently doing it like this:
-behavior(gen_server).
interval_milliseconds ()-> 15000.
init()->
{ok,
_State = FascinatingStateData,
_TimeoutInterval = interval_milliseconds ()
}.
%% This gets called automatically as a result of our handlers
%% including the optional _TimeoutInterval value in the returned
%% Result
handle_info(timeout, StateData)->
{noreply,
_State = do_some_work(StateData),
_TimeoutInterval = interval_milliseconds ()
}.
This works, but it's extremely brittle: if I want to teach my server a new message, when I write any new handler function, I have to remember to include the optional timeout interval in its return value. That is, say if I'm handling a synchronous call, I need to do this:
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever (), interval_milliseconds ()};
instead of
%% Someone wants to know our state; tell them
handle_call(query_state_data, _From, StateData)->
{reply, StateData, _NewStateData = whatever ()};
As you might guess, I've made that very mistake a number of times. It's nasty, because once the code handles that query_state_data message, the timeouts no longer get generated, and the whole server grinds to a halt. (I can "defibrillate" it manually by getting a shell on the machine and sending a "timeout" message by hand, but ... eww.)
Now, I could try to remember to always specify that optional Timeout parameter in my Result value. But that doesn't scale: I'll forget someday, and will be staring at this bug once again. So: what's a better way?
I don't think I want to write an actual loop that runs forever, and spends most of its time sleeping; that seems counter to the spirit of OTP.
Use timer:send_interval/2. E.g.:
-behavior(gen_server).
interval_milliseconds()-> 15000.
init()->
timer:send_interval(interval_milliseconds(), interval),
{ok, FascinatingStateData}.
%% this clause will be called every 15 seconds
handle_info(interval, StateData)->
State2 = do_some_work(StateData)
{noreply, State2}.
The best way is:
init([]) ->
Timer = erlang:send_after(1, self(), check),
{ok, Timer}.
handle_info(check, OldTimer) ->
erlang:cancel_timer(OldTimer),
do_task(),
Timer = erlang:send_after(1000, self(), check),
{noreply, Timer}.
Use the timer module :)

Resources