Stopping/exiting GenServer process

I have a gen server spawned by simple one for one supervisor, and when I return {:stop, {:shutdown, reason}, state} process remains alive, even though terminate/2 callback is called. What am I doing wrong? (if instead of returning :stop tuple I call Supervisor.terminate_child(MySupervisor, self()) process terminates as expected. How do I stop it, and what is the right way?

Does it actually remain alive (same pid), or does it get restarted?

2 Likes

It remains alive and not restarted

terminate/2 could be hanging. If you do Process.info() after the pid tried to stop, what does the backtrace look like?

Is it a call or a cast? I remember having some troubles with the response tupple. Maybe try to change your return value.

There is a call return

{:stop, :normal, state, state}

There is a cast return

{:stop, :normal, state}

BTW simple_one_for_one is going to be deprecated in favor of Dynamic Supervisor. I also had syntax problem, dialyzer warning because of it. simple_one_for_one does not accept new child_spec.

1 Like

looks like ```
[current_function: {:gen_server, :loop, 7},
initial_call: {:proc_lib, :init_p, 5}, status: :waiting, message_queue_len: 0,
messages: [], links: [#PID<0.472.0>],
dictionary: ["$initial_call": {Manager, :init, 1},
“$ancestors”: [ManagerSupervisor,
PipelineSupervisor, MySupervisor, #PID<0.456.0>]],
trap_exit: false, error_handler: :error_handler, priority: :normal,
group_leader: #PID<0.455.0>, total_heap_size: 233, heap_size: 233,
stack_size: 10, reductions: 45,
garbage_collection: [max_heap_size: %{error_logger: true, kill: true, size: 0},
min_bin_vheap_size: 46422, min_heap_size: 233, fullsweep_after: 65535,
minor_gcs: 0], suspending: []]

sorry if that's poorly formatted

I have both callbacks, when I need to stop on call I do {:stop, :shutdown, reply, state} on casts I do {:stop, :shutdown, state}

Yeah, I have a lot of stuff to migrate to Dynamic Supervisor :astonished:

It’s not possible for a gen_server to go back to loop after terminate is called. Are you really sure terminate was called, and the process wasn’t restarted?

2 Likes

How was the child initialised? What’s it restart value? Permanent, temporary or transient?

2 Likes

I’m sorry I’ve wasted your time folks, process is being restarted (Initially I’ve checked the state of the process, and for my surprise state remained from the previous process, so I thought it’s the same one, next I checked observer to verify that pid does not change and it’s the same process, but it actually has changed and new pid was a digit different from the previous one so I did not notice at first… :persevere:)
Later I set restart to temporary and it worked as intended (as @NobbZ pointed out).

One question though, does supervisor keeps initial state of the process? Because said process being restarted with the same state I initialised the previous one.

1 Like

It doesn’t keep state, but it uses the same start function and arguments, so if your initialization is deterministic the process will end up in the same state.

http://erlang.org/doc/man/supervisor.html#start_child-2

For a simple_one_for_one supervisor, the child specification defined in Module:init/1 is used, and ChildSpec must instead be an arbitrary list of terms List. The child process is then started by appending List to the existing start function arguments, that is, by calling apply(M, F, A++List), where {M,F,A} is the start function defined in the child specification.

4 Likes