erlanggen-servereunit

gen_server stop badmatch on sub process stopped


I have a table process which creates a pidfor a board as part of its state with go().

I am testing that terminating the table also terminates the board. But the board is not stopping as expected.

My test:

kills_board_test() ->
  {ok, Table} = table:go(),
  {BoardPid, _ ,_ } = s:s(Table, info),
  gen_server:stop(Table),
  undefined = process_info(BoardPid).

In table.erl I implement:

handle_call(stop, _From, State = {Board, _, _}) ->
    gen_server:stop(Board),
    {stop, normal, shutdown_ok, State};

My result is:

> 6>table_test:test(). table_test: kills_board_test (module
> 'table_test')...*failed* in function table_test:kills_board_test/0
> (table_test.erl, line 8)
> **error:{badmatch,[{current_function,{gen_server,loop,6}},
>            {initial_call,{proc_lib,init_p,5}},
>            {status,waiting},
>            {message_queue_len,0},
>            {messages,[]},
>            {links,[]},
>            {dictionary,[{'$initial_call',{board,init,1}},
>                         {'$ancestors',[<0.351.0>,<0.349.0>]}]},
>            {trap_exit,false},
>            {error_handler,error_handler},
>            {priority,normal},
>            {group_leader,<0.350.0>},
>            {total_heap_size,233},
>            {heap_size,233},
>            {stack_size,9},
>            {reductions,152},
>            {garbage_collection,...},
>            {...}]}   output:<<"Table Terminating.{<0.352.0>,
>                    #{current_player => x,result => playing},
>                    #{o => {<0.355.0>,<0.356.0>},x => {<0.353.0>,<0.354.0>}}} ">>
> 
> =======================================================   Failed: 1.  Skipped: 0.  Passed: 0. error 

EDIT:

I see the text "terminating", but I understood that stop would wait for the termination to complete before returning.


Solution

  • Your custom stop behavior is in handle_call(stop, ...) but you're calling gen_server:stop/1 which will not invoke that code. You probably meant to do gen_server:call(Table, stop) instead.

    That said, you might want to move this stop behavior to Module:terminate/2, which is called automatically by gen_server:stop (unless you have a reason to implement this behavior in a handle_call):

    terminate(_Reason, _State = {Board, _, _}) ->
      gen_server:stop(Board)
    

    Now, gen_server:stop(Table) will invoke this callback and stop the Board automatically.