Difference Between Executors and Supervisors
I am very new to Elixir / Phoenix. I am working on a previously created application that has multi-user repos and today I see an example that makes me wonder what the configuration means
I think I don't know how to search, so I cannot find the correct answer on the documentation
at first the app I am working with has something like
defmodule RestApi do
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [
supervisor(RestApi.Endpoint, []),
supervisor(RestApi.Repo, []),]),
supervisor(RestApi.OtherRepo, []),]),
]
opts = [strategy: :one_for_one, name: RestApi.Supervisor]
Supervisor.start_link(children, opts)
end
def config_change(changed, _new, removed) do
RestApi.Endpoint.config_change(changed, removed)
:ok
end
end
they use Supervisor.Spec.supervisor / 3 function to start / manage everything
later i found an example
defmodule RestApi do
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [
supervisor(RestApi.Endpoint, []),
worker(RestApi.Repo, []),
]
opts = [strategy: :one_for_one, name: RestApi.Supervisor]
Supervisor.start_link(children, opts)
end
def config_change(changed, _new, removed) do
RestApi.Endpoint.config_change(changed, removed)
:ok
end
end
for example they use Supervisor.Spec.worker / 3 to run / manage the repo
What is the difference? I mean, how does the application affect (performance, memory consumption, etc.)
source to share
Think of the supervisor as a branch in the supervision tree and the worksheet as a leaf.
Everyone supervisor
is worker
, not everyone worker
is supervisor
. While it supervisor
has a bunch of features specifically designed to manage child processes, it actually has very little performance impact compared to the general one gen_server
. This excerpt from the OTP Design Principles explains what is supervisor
intended to:
The observer is responsible for starting, stopping, and monitoring its child processes. The main idea behind the supervisor is that it should save its child processes, restarting them when needed.
Which child process is started and monitored is determined by the list of child specifications. Child Processes start in the order shown in this list and end in reverse order.
Also, it is " worker
."
However, there is a rule that is easy to accept: when a process controls child processes, its a supervisor
differently worker
.
In the example given:
children = [ supervisor(RestApi.Endpoint, []), worker(RestApi.Repo, []), ]
RestApi.Endpoint
manages child processes, but RestApi.Repo
not. Also, both are good old gen_server
s.
source to share
You use supervisor
to start processes that are Supervisors and worker
to start workers (basically nothing that is not a supervisor). You can find more information on this in the Supervisor and Supervisor.Spec docs.
Either a process type appears that changes between versions, or one of these examples has a bug, but I believe it should be a workflow, but I would check the Ecto docs.
As far as how this affects the application, there is no meaningful difference other than documentation of the type of process the child has - in fact, it is optional in Erlang. Supervisors manage their own set of child processes, forming an oversight tree. You use this to isolate the effects of failures in subsectors of this tree so that unrelated parts of the application can continue to function while the damaged branch is restarted by its supervisor. It is the source of fault tolerance in the language and is the fundamental building block of OTP.
Workers are by far the most common type of process, they do not manage child processes and are designed to crash and restart their supervisor when things go wrong, the idea is to start from a clean, known state. Too many crashes cause the parent supervisor to crash, which in turn is restarted by its supervisor - if this bubbles up to your application's top-level supervisor, the application will crash.
Hope this helps :)
source to share