Question

I have a supervision tree comprised of gen_servers as temporary children, that have a small lifespan. Each child receives a message when it's time to clean up and terminate.

There is a controller process that keeps a dict of the Pid's from these children, inspired by code I read from tinymq project.

In their case they expire their channels using a max_age setting with some code I don't quite understand.

In my case I am trying to use the supervisor:terminate_child(Sup, Pid), after doing some clean up, as follows:

The child itself, does a RPC on the controller:

fs_outbound_controller:deallocate_me(UUID, self());

controller:

deallocate_me(UUID, Pid) ->
    gen_server:cast(?SERVER, {deallocate_me, UUID, Pid}).

handle_cast({deallocate_me, UUID, Pid}, #state{dict = Uuid2Pid} = State) ->
    NewDict = dict:erase(UUID, Uuid2Pid),
    supervisor:terminate_child(fs_outbound_extn_sup, Pid),
    error_logger:info_msg("Successfully deallocated ~p", [UUID]),
    {noreply, State#state{dict=NewDict}}.

The problem I observe is that the ERROR logger reports a crash in regards the gen_server terminate return value?

** Reason for termination == 
** {bad_return_value,ok}

Your help is appreciated.

EDIT

I did something else, I moved the call to deallocate_me from RPC to a message from the child to the controller. Thinking that maybe the child doing an RPC call to the controller which in turned terminated the child was causing some return issues. The handler remains the same

handle_info({deallocate_me, UUID, Pid}, #state{dict = Uuid2Pid} = State) -> NewDict = dict:erase(UUID, Uuid2Pid), supervisor:terminate_child(fs_outbound_extn_sup, Pid), error_logger:info_msg("Successfully deallocated ~p", [UUID]), {noreply, State#state{dict=NewDict}}.

But still now I get:

** Reason for termination == 
** {bad_return_value,{deallocate_me,"49d9f7cb-62d3-4c3f-abf1-a19848967a9a",
                                    <0.50.0>}}
Was it helpful?

Solution

It seems for me that

fs_outbound_controller:deallocate_me(UUID, self());

is being called as the last statement inside either handle_call/3, handle_cast/2 or handle_info/2. These are expecting something like either {reply, ...}, {noreply, ...} or {stop, ...} as you might know.

Remember that gen_server:cast/2 always returns ok and ServerPid ! Message always returns Message itself. That is why the first time you've been told {bad_return_value, ok} and the second time {bad_return_value, MessageSent}.

In your case I would stick with gen_server:cast way and simply put the right return value right after the erroneous call:

fs_outbound_controller:deallocate_me(UUID, self()),
{noreply, State}; %% strongly depends on what your logic there is
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top