gen_server
documentation on Module:terminate
callback says:
Even if the gen_server process is not part of a supervision tree, this function is called if it receives an 'EXIT' message from its parent. Reason is the same as in the 'EXIT' message.
Here is my handle_info
and terminate
function:
handle_info(UnknownMessage, State) ->
io:format("Got unknown message: ~p~n", [UnknownMessage]),
{noreply, State}.
terminate(Reason, State) ->
io:format("Terminating with reason: ~p~n", [Reason]).
I start this server using gen_server:start
. I assume when I call erlang:exit(Pid, fuckoff)
, it should call terminate
callback function. But it shows:
Got unknown message: {'EXIT',<0.33.0>,fuckoff}
Which means it is calling handle_info
. But when I call gen_server:stop
, everything works as mentioned in documentation. I'm calling my gen_server
from shell. Would you please clarify this?
[UPDATE]
Here is source code of decode_msg
function inside gen_server
. If it receives any 'EXIT' message it should call terminate
function:
decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time], Hib);
{'EXIT', Parent, Reason} ->
terminate(Reason, Name, Msg, Mod, State, Debug);
_Msg when Debug =:= [] ->
handle_msg(Msg, Parent, Name, State, Mod);
_Msg ->
Debug1 = sys:handle_debug(Debug, fun print_event/3,
Name, {in, Msg}),
handle_msg(Msg, Parent, Name, State, Mod, Debug1)
end.
In my case it doesn't call terminate
function.
[UPDATE]
When I start gen_server
using gen_server:start_link()
, sending an exit signal using erlang:exit(Pid, Reason)
will result in calling terminate
call back function which is an expected behaviour. It seems there is a difference in interpreting an exit signal whether a process is linked to its parent or not.
2条答案
按热度按时间k10s72fa1#
Short answer:
If you call the
exit/2
function from inside thegen_server
actor, it behaves as expected based on the documentation and theterminate/2
callback will be called.Long answer:
When you send the exit message from the shell, the
Parent
value of exit tuple is set to the shell process id, on the other hand when you start thegen_server
process form shell itsParent
value is set to its own process id, not the shell process id, therefore when it gets the exit message it doesn't match the second clause of the receive block indecode_msg/8
function so theterminate/6
function is not called and finally the next clause is matched which is callinghandle_msg/5
function.Recommendation:
For getting the
terminate/3
callback called even by sending an exit message to thegen_server
process, you can trap the exit message inhandle_info/2
and then return with stop tuple as follows:3b6akqbq2#
When you start your
gen_server
, its a simple process, so,erlang:exit/1
orerlang:exit/2
work as expected.So, currently your code trap
'EXIT'
signal because this one is send like any other message into the mailbox and matchhandle_info/2
wildcard pattern.If you want more information about that, you can read
gen_server
source code and see how it works. You can also find your problem described in this code.