I was practicing with this example.
https://github.com/kwmiebach/how-to-elixir-supervisor
I followed the instruction and got the idea of how it works, but I can't understand how Supervisor, GenServer and Application are different to each other exactly.
Can someone explain how these 3 are different and when they should be used?
In Elixir, this is done by a Supervisor. A Supervisor is a process that supervises other processes and restarts them whenever they crash. To do so, Supervisors manage the whole life-cycle of any supervised processes, including startup and shutdown.
What is OTP? OTP is an awesome set of tools and libraries that Elixir inherits from Erlang, a programming language on whose VM it runs. OTP contains a lot of stuff, such as the Erlang compiler, databases, test framework, profiler, debugging tools.
Basically, you would usually use (many) GenServer to manage state and "do actual work" in your application. A supervisor is a process which supervises other processes, which we refer to as child processes.
GenServer is usually considered as the basic runtime building block for applications implemented with Elixir. Although in fact it's a wrapper around the lower-level Erlang Process primitives, however, GenServer provides many advanced features like debugging and tracing in a standard interface.
A supervisor is a process which supervises other processes, which we refer to as child processes. Supervisors are used to build a hierarchical process structure called a supervision tree. Supervision trees provide fault-tolerance and encapsulate how our applications start and shutdown.
That's why Elixir allows you to pass a tuple with the module name and the start_link argument instead of the specification: The supervisor will then invoke Stack.child_spec ( [:hello]) to retrieve a child specification.
First of all, these are all "OTP Design Principles" (and supported with a standard library), they are all wrappers (or better put, abstractions) on top of basic Erlang primitives like processes. This means they are not the only way to program in Erlang (hence Elixir), but they're shared by the community and backed by decades of battle-tested real-world systems. So you should use them too.
GenServer
is usually considered as the basic runtime building block for applications implemented with Elixir. Although in fact it's a wrapper around the lower-level Erlang Process primitives, however, GenServer
provides many advanced features like debugging and tracing in a standard interface. Basically, you would usually use (many) GenServer
to manage state and "do actual work" in your application.
Supervisor
, as the documentation suggests:
A supervisor is a process which supervises other processes, which we refer to as child processes. Supervisors are used to build a hierarchical process structure called a supervision tree.
So in a sense, it "manages" GenServer
s, but also other Supervisor
s (and other Erlang Process abstractions, if they implement proper interface). You usually don't put any custom logic in Supervisor
modules, partly because their role is very focused - just manage child processes' life cycles. But also to make it less prone to errors (introduced by your changes).
Say it in another way, Supervisor
doesn't do any actual "work" for your application, it's just used to "layout" the architecture of a system.
Compared to the others, Application
is not necessarily a "runtime concern", as the Erlang documentation suggests:
... make the code into an application, that is, a component that can be started and stopped as a unit, and which can also be reused in other systems.
So Application
is really about bundling stuff into a "unit", and real systems are usually composed of many such units - for example whenever you run some Elixir code, there is also an "elixir" Application
which runs several processes such as elixir_code_server
:
More importantly, Application
is THE way to share (reuse) code in OTP design principles. When you define an application, it can have a "root supervisor", which is started together with the application. Or it can also just have functional codes, without running any processes at all, like a JSON library. Either way, to reuse code across different systems, they need to be packaged into Application
s.
Finally, I'd suggest give this a read: https://ferd.ca/the-zen-of-erlang.html it explained (at least for me) how we go from basic (Erlang) processes, to supervisors (and supervision tree), and a little bit of OTP applications. (And how we should approach programming within BEAM)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With