Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Scenic City Summit Elixir OTP

workshop.livemd

Scenic City Summit Elixir OTP

import IEx.Helpers

Scenic City course

1 + 1
input = 42
input + 1
  • (c)onstruct
  • (r)educe?
  • (c) ?
defmodule Acc do
  def new(s) when is_bitstring(s) do
    String.to_integer(s)
  end

  def new(int) when is_integer(int) do
    int
  end

  def add(acc, i) when is_integer(i) do
    acc + i
  end

  def inc(acc) do
    add(acc, 1)
  end

  def dec(acc) do
    add(acc, -1)
  end


  def show(acc) do
    "The ants arr is #{acc}"
  end

end
import Acc

two_steps_forward_and_one_back = 
  input 
  |> new() 
  |> inc() 
  |> inc() 
  |> dec()
  |> show()
list = [1, 1, -1]

input = 42

Enum.reduce(list, input, &Acc.add/2)

Build a counting service

defmodule Service do

  def start(input) do
    count = input |> Acc.new()

    spawn(fn -> loop(count) end)
  end

  def inc(pid) do
    send(pid, :inc)
  end

  def dec(pid) do
    send(pid, :dec)
  end

  def show(pid) do
    send(pid, {:show, self()})
    receive do
      m -> m
    end
  end

  def loop(count) do
    count
    |> listen()
    |> loop()
  end

  def listen(count) do
    receive do
      :inc -> 
        Acc.inc(count)
        
      :dec -> 
        Acc.dec(count)
      {:show, from_pid } -> 
        # send back the count to the user
        message = Acc.show(count)
        send(from_pid, message)
        # return the current count so our recursion doesn't blow up
        count
    end
  end
end
livebook = 
  self()
Process.info(livebook)
count = 12
message = :dec

send(livebook, message)
Service.listen(count)
count = 11

message = {:show, self()}
send(self(), message)

Service.listen(count)
receive do 
  m -> m 
end
service = Service.start(input)
Process.alive?(service)
send(service, {:show, self()})
send(service, :inc)
send(service, {:show, self()})

receive do 
  m -> m
end
Service.show(service)

OTP GenServer

defmodule Server do
  use GenServer

  # client

  def start_link(input) do
    GenServer.start_link(Server, input)
  end

  def inc(pid) do
    GenServer.cast(pid, :inc)
  end

  def dec(pid) do
    GenServer.cast(pid, :dec)
  end

  def show(pid) do
    GenServer.call(pid, :show)
  end



  # api stuff will all go here

  # server

  # construct
  @impl true
  def init(input) do
    initial_state = Acc.new(input)
    {:ok, initial_state}
  end

  # reduce

  @impl true
  def handle_cast(:inc, count) do
    new_state = Acc.inc(count)
    {:noreply, new_state}
  end

  @impl true
  def handle_cast(:dec, count) do
    new_state = Acc.dec(count)
    {:noreply, new_state}
  end


  # convert

  @impl true
  def handle_call(:show, _from_pid, count) do
    message = Acc.show(count)
    {:reply, message, count}
  end

  
end
{:ok, pid} = Server.start_link(input)
GenServer.cast(pid, :inc)
GenServer.cast(pid, :inc)
GenServer.cast(pid, :inc)
GenServer.call(pid, :show)
Server.inc(pid)
Server.inc(pid)
Server.inc(pid)
Server.inc(pid)
Server.inc(pid)
Server.show(pid)
:sys.get_state(pid)
h GenServer

OTP Lifecycle (supervision)