Irrespective of this topic, I try to avoid a supervision tree in the lib app as much as possible. In most cases it’s better to provide the API for starting a supervisor process and leave it to the user of the lib to inject that process in their own supervision tree. This allows much more flexibility, b/c the client can leverage the supervision tree to start/stop processes when they want. The most frequent exception to this I’ve experienced is a global process registry. If I need that, I’ll typically start it in the lib’s supervision tree, because it keeps the API simpler, with no particular downsides.
Yeah, it’s fine if you have good reasons.
In a well designed tree a parent process should never be brutally killed. However, if you’re not trapping exits, a parent process could receive a shutdown exit signal from its own parent, and exit immediately. The child will terminate a bit after that. However, it’s possible that in the meantime a new parent has already been restarted, and that it has started a new child. So you might end up with a brief period of two incarnation of the child running at the same time. Or, if the child is registered, a new child may fail to start. To prevent this, a parent should trap exits. In this case, the exit signal from its own parent will be converted into a terminate callback (this is automatically done by behaviours such as GenServer).
If a parent is manually shutting down its child in terminate (as it should), then yes, the parent should wait for the child to stop.
IMO a parent process should always be configured with the shutdown: :infinity to prevent this situation (this is btw a default for supervisors). Otherwise, the parent may be killed forcefully, and you end up with the same subtle race condition as explained earlier.
Not that I can think of.
This won’t work as sketched, because you need a sibling proc, not the parent pid. Getting that proc is a bit tricky, because you can’t invoke e.g. Supervisor.which_child from the child’s start_link (it would cause a deadlock), so you need to do it in handle_continue.
This would be more like it. I used to do this at some point, but then I figured that all these extra supervisors don’t bring a lot of benefits, but at the same time the code becomes more complicated.
You don’t need to jump into Parent. You could instead try to implement it yourself by trapping exit, starting the child process directly, and handling exit messages. I basically wrote Parent after becoming fed up with doing this repeatedly in the scenarios where I had to handle multiple children ![]()
Parent API is exposed in layers. Most of the logic is in fact implemented in the foundational imperative Parent module. Mixing in that capability in your own gen_statem (or other behaviours such as GenStage) should be straightforward, both with or without creating a generic Parent.GenStatem.






















