kasperkronborg
Supervisor without any children
I was looking over the source code for plug_cowboy and saw that in the Plug.Cowboy.start/2 they return a supervisor without any children Supervisor.start_link([], strategy: :one_for_one). What’s the reasoning for doing that?
I’m somewhat new to Elixir, so really interested in learning.
Thanks!
Marked As Solved
msimonborg
After looking at the source code this is my impression, I could be off on some or all aspects but I think this is generally correct.
Plug.Cowboy provides Plug.Cowboy.child_spec/1. When you add Plug.Cowboy to your supervision tree it starts a listener. Here’s some informative documentation and example from the library, found in lib/plug/cowboy/drainer.ex
defmodule Plug.Cowboy.Drainer do
@moduledoc """
Process to drain cowboy connections at shutdown.
When starting `Plug.Cowboy` in a supervision tree, it will create a listener that receives
requests and creates a connection process to handle that request. During shutdown, a
`Plug.Cowboy` process will immediately exit, closing the listener and any open connections
that are still being served. However, in most cases, it is desirable to allow connections
to complete before shutting down.
This module provides a process that during shutdown will close listeners and wait
for connections to complete. It should be placed after other supervised processes that
handle cowboy connections.
...
## Examples
# In your application
def start(_type, _args) do
children = [
{Plug.Cowboy, scheme: :http, plug: MyApp, options: [port: 4040]},
{Plug.Cowboy, scheme: :https, plug: MyApp, options: [port: 4041]},
{Plug.Cowboy.Drainer, refs: [MyApp.HTTP, MyApp.HTTPS]}
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
"""
This seems to cover all or most of the supervision and process generation that Plug.Cowboy provides, which happens inside your own app’s supervision tree (in most cases through Phoenix.Endpoint, probably). It doesn’t explain Plug.Cowboy’s childless supervisor. If we look at the Plug.Cowboy.start/2 callback where the supervisor is defined:
require Logger
@doc false
def start(_type, _args) do
Logger.add_translator({Plug.Cowboy.Translator, :translate})
Supervisor.start_link([], strategy: :one_for_one)
end
Plug.Cowboy is using the start callback to hook into the application lifecycle and add functionality to Logger. From what I can see, this is the sole reason for starting the Plug.Cowboy application. The Supervisor satisfies the application behaviour’s expected return values from start/2.
I scanned the source files (there are only 5 and they’re mostly short, thankfully
) and didn’t see a reference to starting processes under this supervisor. It doesn’t have any name registration either, which would make that unnecessarily hard to achieve.
Also Liked
hauleth
Not really. You can add children dynamically to “regular” supervisors as well. The thing is that if you add them to “regular” one it is assumed that these will live forever rather than being temporary.
josevalim
This is correct. Great spelunking @msimonborg!
kasperkronborg
Thank you for your thorough explanation.
I also went looking through the source code and didn’t seem to find indications of children ever being added to the supervisor.
So what you are saying is that it’s just there to fulfill the expected return of the start/2 callback?
msimonborg
hauleth
My comment was just about the fact that you do not need DynamicSupervisor for dynamic children list. I think that @msimonborg has the correct answer why the supervisor is started with empty children list, it is just for the configuration, not runtime stuff.







