DEV Community

Elxpro
Elxpro

Posted on • Edited on

If you want to understand how Elixir Apps work, this is the way

Before you read this Article, I highly recommend you read the article about GenServer:
https://dev.to/postelxpro/read-this-article-if-you-want-to-learn-genserver-1l24

Do you want to learn Elixir in three months? https://elxpro.com/sell

Greeting

Hello #devElixir!!! Welcome to #FullStackElxpro

Here, we discuss strategies and tips for your Elixir learning journey from zero to an expert in 3 months.

I am Gustavo, and today's theme is **Setup your local machine to use Elixir**.

ps: You can follow the Article with a VIDEO

Want to learn more about Elixir on a Telegram channel?

https://elxpro.com/subscribe-elxcrew

What is the difference between Supervisor and DynamicSupervisor?

Before understanding the difference between Supervisor and DynamicSupervisor. Let`s read and understand both.

Supervisor

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html

A supervisor is a process that supervises other processes, which we refer to as child processes. Supervisors are used to building a hierarchical process structure called a supervision tree. Supervision trees provide fault tolerance and encapsulate how our applications start and shut down.

In my experience as a Developer in general, Supervisor is a way to keep the lifecycle of my Elixir Web Applications and a way to start and manage the essential dependencies you will have in your App. E.g., Ecto, Phoenix, Oban, Broadway.

Suppose you understand how Supervisor Works. It will be much easier to create dependencies of processes and how to start them quickly. Building Elixir applications and understanding core frameworks will be more straightforward in that case.

DynamicSupervisor

A DynamicSupervisor starts with no children. Instead, children are started on demand via start_child/2. When a dynamic supervisor terminates, all children are shut down at the same time, with no guarantee of ordering.

https://hexdocs.pm/elixir/1.13/DynamicSupervisor.html
https://elixir-lang.org/getting-started/mix-otp/dynamic-supervisor.html

DynamicSupervisor starts the process when is necessary, and you can see it easily when you have a Browser opened or a query execution using Ecto. I like creating associations during our typical day as an Elixir Developer because most of the time you will not use DynamycSupervisor/Supervisor. But they are there, you are using them, and you probably will need to debug or understand a piece of code in our core frameworks like ECTO/Phoenix or others. That is why understanding the difference between them and maybe in a day use them.

What's worth more? Use Supervisor or DynamicSupervisor

I think you will use both but in a different context


Do you remember any stories where this was important to you?

Yes, I do. I remember when I knew only to use Phoenix and Ecto barely, and I had some problems with those frameworks and lifecycles. And also, I was encouraging myself to learn deeply about how Phoenix, Ecto, and Elixir work.

I had no idea why the application.ex was in my phoenix applications, no idea how the process and supervisors tree works, no idea how a phoenix app works. And I lost a lot of productivity in my day as an Elixir developer because I did not know why/how they worked and why they were there. When I decided to study how they worked and research both, my life as an Elixir developer changed. Elixir's level of skill and productivity was raised 10x more because I only understood how they work.


Where do you see people get it wrong the most?

The main problem is you feel comfortable using only libs like Phoenix and Ecto for more than 10 months. Because if you don`t understand how your elixir application works, you will face problems scaling apps using dependencies like Oban, Broadway, or frameworks to use Cache, MongoDb, and even simple GenServer.

The best way in my experience is:

  • Am I okay to create standard Phoenix Apps?
  • Now I am going to study how Process works.
  • Do I know how to make a GenServer/Agents and Tasks? I am going to look at it.
  • Do I understand how Supervisor and DynamicSupervisor work? I am good at learning it.

Where to start?

Level 1

Start a standard Elixir app

❯ mix new practice                                       

Enter fullscreen mode Exit fullscreen mode

and create a GenServer

defmodule StocksV1 do
  use GenServer

  def start_link(name: name, valuation: valuation) do
    GenServer.start_link(__MODULE__, valuation, name: name)
  end

  def init(state) do
    {:ok, state}
  end

  def handle_cast({:add, value}, state) do
    state = state + value
    {:noreply, state}
  end

  def add(stock, value) do
    GenServer.cast(stock, {:add, value})
  end
end

Enter fullscreen mode Exit fullscreen mode

Lets Play around with our Genserver.

iex(4)> StocksV1.start_link name: :etsy, valuation: 10

iex(5)> :sys.get_state :etsy

iex(6)> GenServer.cast :etsy, {:add, 30} 

iex(7)> :sys.get_state :etsy
Enter fullscreen mode Exit fullscreen mode

How about we want to start our stock within our App?

In this case, we can use Supervisor but how to start it?

It is simple, but we need to use the application because we are learning the whole process we need to use the application. And Application is essential for our Libs and Elixir application.

Read more: https://hexdocs.pm/elixir/1.13/Application.html

Applications are the idiomatic way to package software in Erlang/OTP. To get the idea, they are similar to the "library" concept common in other programming languages, but with some additional characteristics.

straightforward to use it, you only need to add in your mix.exs

  def application do
    [
      extra_applications: [:logger],
      mod: {Practice.Application, []}
    ]
  end
Enter fullscreen mode Exit fullscreen mode

create application.ex

defmodule Practice.Application do
  use Application

  def start(_, _) do
    children = []
    Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
  end
end

Enter fullscreen mode Exit fullscreen mode

Every time that you create an Application you must create an :erlang.link and in this case our link is our Supervisor. After starting the Supervisor you can only add your process to run:

defmodule Practice.Application do
  use Application

  def start(_, _) do
    children = [
      {StocksV1, name: :etsy, valuation: 10},
      # {StocksV1, name: :appl, valuation: 10}
    ]
    Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
  end
end
Enter fullscreen mode Exit fullscreen mode

But you will notice that one of them is commented because you need IDS, and we can`t start it when we want but when we start the application, which makes us move to the next step. Start using DynamicSupervisors.

`
defmodule Practice.Application do
use Application

def start(_, _) do
children = [
{Registry, keys: :unique, name: Stocks},
{DynamicSupervisor, strategy: :one_for_one, name: Stocks.DynamicSupervisor}
]

Supervisor.start_link(children, strategy: :one_for_one, name: __MODULE__)
Enter fullscreen mode Exit fullscreen mode

end
end
`

`
defmodule Stocks do
use GenServer

def start_link(name: name, valuation: valuation) do
name = stock_name(name)
GenServer.start_link(MODULE, valuation, name: name)
end

def stock_name(name) do
{:via, Registry, {MODULE, name}}
end

def init(state) do
{:ok, state}
end

def handle_cast({:add, value}, state) do
state = state + value
{:noreply, state}
end

def create_stock(name, valuation \ 20) do
DynamicSupervisor.start_child(
Stocks.DynamicSupervisor,
{Stocks, [name: name, valuation: valuation]}
)
end

def add(stock, value) do
stock = stock_name(stock)
GenServer.cast(stock, {:add, value})
end
end
`

When you call create_stock, different of a GenServer, you will create a child for your DynamicSupervisor and then. Create a process_id linking to your Parent's process.

`
iex(1)> Stocks.create_stock "apple", 100
{:ok, #PID<0.175.0>}

iex(2)> Stocks.create_stock "alphabet", 300
{:ok, #PID<0.177.0>}

iex(3)> :sys.get_state pid("0.175.0")
100
`

Because we are using Registry, the way that we are creating processes is different. that is why we have the function stock_name, creating the unique ID to our process and then change the state.


iex(4)> Stocks.add "apple", 300
:ok
iex(5)> :sys.get_state pid("0.175.0")

Wrap up

If you followed this article, you will notice how simple is to use both of the services when you understand how the process works.

Social networks:

Top comments (0)