autodidaddict
Proper pattern for terminating children of a dynamic supervisor
I’ve reviewed the other topics here and done a bunch of googling and haven’t been able to find out the right way to deal with this.
I have DynamicSupervisors , about 4-5 of them. Each of those spawns GenServers as children via DynamicServer.start_child.
What I then need to be able to do is expose a function in the supervisor that will terminate a child by key, so it needs to: a) look up the child (this works fine), b) terminate the child.
The problem is I can’t figure out how to “cleanly” and “idiomatically” terminate the child process. In my terminate_child_by_key(foo) function, what’s the accepted way of shutting that pid down? Not only do I need to shut that pid down, but I need to be able to publish a message on my broker so that I can emit the “child died” event.
Since I’m going to do this over and over again, I want to do it right. I’ve tried using Process.flag(..) in the child as a way of getting advance notice that the child is going to die but that handle_info never gets called. When I use process flag in the supervisor, the supervisor never gets called during child death.
Additionally, for this scenario, I can’t use transient children (?) because they come back immediately after I kill them… the behavior I want is when I choose to kill the child, it’ll stay dead, but when it dies due to exception failure, it’ll restart.
Any advice would be greatly appreciated as I’ve been doing this all in a very ugly fashion and I don’t want to continue repeating that same ugliness all over my code base.
Most Liked
autodidaddict
Thanks for all the information here! I ended up deciding not to use Process.exit. Instead I followed @ityonemo 's suggestion of sending a “soft halt” by doing a GenServer.call(pid, :halt_and_cleanup) , this gives me the handle_call for this explicit type of termination, which in turn lets me publish the “child died” message on my broker and then safely return {:stop, :normal, :ok, state}.
I also adopted the use of the Registry and I’m now storing the child pids there along with their keys.
al2o3cr
If the process is actively handling messages (versus being blocked in a call or similar), consider adding an explicit “hey could you please shut down” message to the GenServer’s public API. The handle_call head for that can return {:stop, :shutdown, :ok, state} and the GenServer will exit with reason :shutdown.
Otherwise, signaling from outside is done via Process.exit/2 and functions built using it. It’s useful to understand exactly what “signaling a process to exit means”:
-
If any Erlang process gets an exit signal with a reason of
:kill, it will exit immediately with the reason:kill. -
If a process that isn’t trapping exits gets an exit signal, it will exit immediately with the same reason.
-
If a GenServer is trapping exits, the built-in handler from
gen_serverwill invoke theterminate/2callback with the reason. (more info)
(the above is summarized from The many and varied ways to kill an OTP Process | The log of Paul Wilson )
The idiomatic sequence implemented by terminate_child in DynamicSupervisor and Supervisor is:
Process.exit(pid, :shutdown)- wait for the
:DOWNmessage - if it doesn’t arrive (default in 5s),
Process.exit(pid, :kill)
Prefer using those functions over building custom Process.exit setups unless you have a real good reason.
Re: reanimating processes - restart: :transient will restart the process if it exits with a reason other than :normal, :shutdown, or {:shutdown, term()} - for instance, if the process doesn’t respond to the :shutdown signal and gets killed. If that’s undesirable, consider restart: :temporary instead.
One final note: pay close attention to the gotchas listed in the terminate callback’s documentation. If you need a 100% reliable “GenServer went away” hook, consider using Process.monitor and handling the {:DOWN, ...} message.
axelson
Have you tried using DynamicSupervisor.terminate_child/2?
If you’re stopping a transient child cleanly then it should not be restarted.
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









