Skip to content

DynamicSupervisor: the option "max_restarts" only work if provided as initial argument #13675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JoeZ99 opened this issue Jun 18, 2024 · 9 comments · Fixed by #13678
Closed

Comments

@JoeZ99
Copy link
Contributor

JoeZ99 commented Jun 18, 2024

Elixir and Erlang/OTP versions

elixir 15.4
otp 26

Operating system

linux

Current behavior

When specifying the "max_restarts" option as a regular when using DynamicSupervisor, it doesn't work.

How to check?

Have this two modules:

defmodule Test2 do             
  use GenServer                                                                                                                         
                                                                                                                                                    
  def start_link(_opts \\ []) do                                                                                                    
    GenServer.start_link(__MODULE__, [])                                                                                            
  end                                                                                                                               
                                                                                                                                    
  def init(_opts \\ []) do     
    Process.send_after(self(), :boom, 2000)    
    {:ok, :ok}                                                                                           
  end                          
                                                                                                                                                                               
  def handle_info(:boom, _), do: raise "Boom!"    
end  

and

defmodule Pipo do              
  def start(options_mr, args_mr) do                                                                                                     
    do_start(options_mr, args_mr)                                                                                                                   
  end                                                                                                                               
                                                                                                                                    
  @impl true                                                                                                                        
  def init(args_mr) do                                                                                                              
    DynamicSupervisor.init(max_restarts: args_mr, strategy: :one_for_one, max_seconds: 10)    
  end                                          
                                                                                                         
  def add_children do          
    DynamicSupervisor.start_child(__MODULE__, Test2)                                                                                                                           
  end                                             
                                                                                                         
  defp do_start(options_mr, args_mr) do    
    DynamicSupervisor.start_link(__MODULE__, args_mr, name: __MODULE__, max_restarts: options_mr)    
  end    
end    

an then on a shell, do:

iex> Pipo.start(100,3)
iex> Pipo.add_children

and you'll see how it explodes only three times (because after 3 restarts, the dynamicsupervisor dies), in spite of you specifying "100" restarts in the options

however, if you do:

iex> Pipo.start(3, 100)
iex> Pipo.add_children

you'll see it restarts the children more than three times.

Expected behavior

Based on documentation, I expect that providing max_restarts as regular option:

DynamicSupervisor.start_link(__MODULE__, _init_args, max_restarts: 100)

would work

But only work if provided as initial option:

DynamicSupervisor.init(max_restarts: 100)
@josevalim
Copy link
Member

For clarity, Can you please link to the documentation that implied max_restarts work on start_link/3? Thank you!

@paulo-ferraz-oliveira
Copy link

@josevalim, I think it comes from

@spec start_link([option() | init_option()]) :: Supervisor.on_start()

where :max_restarts is indeed seen as an init_option() element: https://hexdocs.pm/elixir/1.17.1/DynamicSupervisor.html#start_link/1

@josevalim
Copy link
Member

But that’s start_link/1, right?

@paulo-ferraz-oliveira
Copy link

But that’s start_link/1, right?

You're right. I mis-read it 😄 Maybe the OP did too 🤷 😄 Sorry for the noise.

@JoeZ99 JoeZ99 changed the title DynamicSupervisor: the option "max_restarts" only work is provided as initial argument DynamicSupervisor: the option "max_restarts" only work if provided as initial argument Jun 18, 2024
@JoeZ99
Copy link
Contributor Author

JoeZ99 commented Jun 19, 2024

Well, it's not so much a bug or a bad doc, but more like it's easy to confuse option with init_option in the docs, and the confusion of @paulo-ferraz-oliveira is a perfect example of that...

First and foremost, the people from https://github.com/arjan/singleton has suffered the same confusion (in fact, that's how I got -after 2 weeks- to nail this 😄 ), if you look at https://github.com/arjan/singleton/blob/master/lib/singleton/supervisor.ex#L25 and https://github.com/arjan/singleton/blob/master/lib/singleton/supervisor.ex#L25, you'll see that they intend to use max_restarts as an option to be passed to start_link/3

I've tried to read about it in the docs, and I find it at least slightly misleading...

So, in a nutshell, I can't exactly "blame" the doc, but I think it's very easy to get confused and assume option and init_option are the same, and I'd rather be more explicit about the difference on init_option and option, which now can only be perceived if you link in the specs ....

@josevalim
Copy link
Member

Hi @JoeZ99! No worries, we can totally blame the docs! They can always improve and that's the biggest question: how could we improve them? Would you like to try a PR? I would be glad to review it.

@JoeZ99
Copy link
Contributor Author

JoeZ99 commented Jun 19, 2024

hey @josevalim , txs!!!

I've made a PR: #13678, but I don't know what else to do ... Another thing is that this "doc improvement" is to be read at least since version 1.15.4 of elixir, I don't know if I should make a PR for that tag and every subsequent one ...

@JoeZ99
Copy link
Contributor Author

JoeZ99 commented Jun 19, 2024

But that’s start_link/1, right?

You're right. I mis-read it 😄 Maybe the OP did too 🤷 😄 Sorry for the noise.

what does "OP" mean 😄 ????

@josevalim
Copy link
Member

I believe it means "Original Poster", so it was referring to you. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging a pull request may close this issue.

3 participants