christhekeele
I ran into a situation recently where it would be very useful to start up a DynamicSupervisor in an application’s sup tree, always with a specific list of child specs to boot on init—much the way normal Supervisors work, but with the option to dynamically start new children easily later.
I started writing a question on how to do so… Which turned into an experiment with handle_continue (since DynamicSupervisor is implemented as a GenServer)… Which turned into a half-written proposal to the core mailing list… Which turned into an incomplete proof-of-concept fork implementing support for this within Elixir… Before discovering that during the development of DynamicSupervisor, support for this was intentionally dropped because of technical difficulties expanding child specifications at boot time.
Problem is, I’m not sure I understand the original motivation or the difficulties in doing so. Based on my toy branch I had no difficultly using the existing validate_child logic to expand child specs given at init, so either the implementation of DynamicSupervisor has changed enough to overcome the obstacles present when it was first created, or (more likely) I’m missing something obvious that still prohibits it today.
(The implementation in my fork uses handle_continue when it doesn’t need to, and in fact shouldn’t, but that’s the circuitous route I took to get here. It’d be reworked in a proper PR.)
Does anyone have any insight into if and why we couldn’t pass DynamicSupervisor’s init procedure a list of child specs to boot at start? Perhaps you can explain the original rationale in a way I understand better? (Without spam @'ing them) do any of the original implementers mind chipping in? I’m reluctant to work more on a PR/open a feature proposal in the core mailing list without fully understanding why this was decided against originally.
Trending in Questions
Other Trending 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
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










First 7 of 7 Posts
josevalim
I would suggest to start a DynamicSupervisor with a Task under a rest_for_one supervisor. This way you can start children immediately after the supervisor boots. IIRC that was the main reason to keep the DynamicSupervisor API simpler, since this behaviour is not common and it can be easily replicated.
Phillipp
I also have a DynamicSupervisor which needs to start some children on app startup.
For that I used the module based DynamicSupervisor so I can hook into the init function like that:
My Manager is in itself a GenServer, here are some snippets from my code:
christhekeele
Ooh, that’s better than how I was doing this, thanks!
One interesting thing I realized while tinkering around with implementing support for this is that doing so makes the behaviour contract for
DynamicSupervisormatch that ofSupervisor(by returning a list of children + options ininit/1).I agree this behaviour is not common and most apps don’t need such a feature, but it does provide a compelling ‘upgrade path’ from a Supervisor to DynamicSupervisor: just replace the module name in
use SupervisorandSupervisor.init, with the knowledge that any callback returns crafted by hand (instead ofSupervisor.init) will continue to work since both callbacks now accept the same shape.Then you could begin converting a Supervisor to a DynamicSupervisor with the knowledge that any children you were relying upon to be started initially in your supervision tree still will be as you gradually refactor how they are launched.
Of course, this is solving a problem I don’t think exists, I just find the parity and parallels pretty—agreed it’s probably not worth complicating the implementation for.
iautom8things
Just in case someone else (like me) happens upon this thread looking for guidance, but doesn’t quite grok what José is suggesting (also like me, initially):
I happened to find this great TIL repo by @slashdotdash that gives you a working example:
https://github.com/slashdotdash/til/blob/master/elixir/dynamic-supervisor-start-children.md
Thank you, everyone!
Linuus
I tried this but it doesn’t seem to work? It just restarts my DynamicSupervisor and not my Task.
Is it because the Task has already finished so it can’t be “restarted”?
My Supervisor looks like this:
edisonywh
I think it’s because of the restart strategy of the Task module, here’s the documentation:
You can simulate this by creating a Task module yourself,
Then put in in your supervision tree like normal
{MyTask, []}. Kill the first process and you’ll see that MyTask doesn’t restart, then now try with therestart: :transientflag, and you’ll see it worksbrentjanderson
This thread helped me recently, and I wanted to add in that a
Taskwill run asynchronously, whereas you can do the same thing with anAgent.If you want to block while adding the initial children to the DynamicSupervisor, this is one way to do it.