Question

I have a gen_server which wraps a port. The gen_server's terminate/2 callback it calls port_close(Port) to ensure the port is closed. If the port has already been closed (which would cause the gen_server to stop), my understanding is this will throw a bad_argument exception. To deal with this, I use the expression catch port_close(Port). However, you guessed it, the exception is still being thrown.

The code:

terminate(Reason, #state{port=Port}) ->
    lager:info("Terminating ~p due to ~p", [?MODULE, Reason]),
    catch port_close(Port).

And the exception:

6:31:03.034 [error] CRASH REPORT Process <0.69.0> with 1 neighbours exited with reason: bad argument in call to erlang:port_close(#Port<0.3906>) in my_gen_server:terminate/2 line 62 in gen_server:terminate/6 line 725
** exception error: bad argument
     in function  port_close/1
        called as port_close(#Port<0.3906>)
     in call from my_gen_server:terminate/2 (src/my_gen_server.erl, line 62)
     in call from gen_server:terminate/6 (gen_server.erl, line 722)
     in call from proc_lib:init_p_do_apply/3 (proc_lib.erl, line 227)

The same error occurs whether Reason = normal | term()

I'd be very thankful for any advice as to why this is not being caught!

Was it helpful?

Solution

Well, the answer is I need a different return value, in this case ok.

terminate(Reason, #state{port=Port}) ->
    lager:info("Terminating ~p due to ~p", [?MODULE, Reason]),
    catch port_close(Port),
    ok.

I'm still a bit confused since the documentation states for terminate/2 that The return value is ignored.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top