Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducing Elixir: Self-healing applications at ZOMG scale

Introducing Elixir: Self-healing applications at ZOMG scale

Elixir is a new functional language built on the Erlang VM. We’ll tour the Elixir language and it’s most important frameworks to discover what makes Elixir a great choice for building systems at ZOMG scale and how those systems stay up for so long with Wolverine level self-healing.

Elixir’s secret is in its Erlang heritage. When was the last time your telephone network went down? Never, right? That’s because most of the telephone network is written in Erlang. How does WhatsApp manage to support 1.2 billion users and deliver 42 billion messages a day with only around 50 engineers? Yes, Erlang.

Elixir takes the power and stability offered by Erlang and makes it more approachable, with a Ruby inspired syntax, simpler abstractions and some powerful tools which will enable you to build concurrent, fault-tolerant and distributed systems. We'll find out how this functional language is the most Object Oriented of all languages and how microservice architecture is built right in.

Challenge yourself to break out of your comfort zone and look at how other languages solve problems. You’ll become a better developer if you do.

Andy Pike

June 10, 2017
Tweet

More Decks by Andy Pike

Other Decks in Programming

Transcript

  1. $ iex iex(1)> $ iex hello.exs iex(1)> Hello.world() "Hello World"

    iex(2)> h String.upcase Converts all characters in the given string to uppercase. ## Examples iex> String.upcase("abcd") "ABCD"
  2. $ iex iex(1)> 1 + 1 2 iex(2)> 2 *

    3 6 iex(3)> 1.2 - 0.2 1.0 iex(4)> 1..10 1..10 iex(5)> "Hello World" "Hello World" iex(6)> :andy :andy
  3. iex(1)> { :ok, 42, "next" } { :ok, 42, "next"

    } iex(2)> [1, 2, 3] [1, 2, 3] iex(3)> [1, 2, 3] ++ [4, 5, 6] [1, 2, 3, 4, 5, 6] iex(4)> info = %{ :name => "Andy", :town => "Woking" } %{name: "Andy", town: "Woking"} iex(5)> info[:name] "Andy" iex(6)> info.name "Andy"
  4. person.exs defmodule Person do
 defstruct name: "", age: 0, email:

    "" end $ iex person.exs iex(1)> p1 = %Person{ name: "Andy", age: 25 } %Person{age: 25, email: "", name: "Andy"} iex(2)> p1.name "Andy" iex(3)> p2 = %Person{ p1 | email: "[email protected]" } %Person{age: 25, email: "[email protected]", name: "Andy"} iex(4)> p1.email ""
  5. iex(1)> a = 1 1 iex(2)> a + 2 3

    iex(3)> a = 2 2 iex(4)> 2 = a 2 iex(5)> 3 = a ** (MatchError) no match of right hand side value: 2 iex(6)> ^a = 3 ** (MatchError) no match of right hand side value: 3
  6. iex(1)> list = [1, 2, 3] [1, 2, 3] iex(2)>

    [x, y, z] = list [1, 2, 3] iex(3)> y 2 iex(4)> [1, b, c] = list [1, 2, 3] iex(5)> b 2 iex(6)> [3, t, 5] = list ** (MatchError) no match of right hand side value: [1, 2, 3]
  7. iex(1)> success = { :ok, 42 } { :ok, 42

    } iex(2)> failure = { :error, "Oops" } { :error, "Oops" } iex(3)> { :ok, result } = success { :ok, 42 } iex(4)> result 42 iex(5)> { :ok, result } = failure ** (MatchError) no match of right hand side value: {:error, "Oops"} iex(6)> { _, result } = failure { :error, "Oops" }
  8. iex(1)> list = [1, 2, 3] [1, 2, 3] iex(2)>

    [head|tail] = list [1, 2, 3] iex(3)> head 1 iex(4)> tail [2, 3] iex(5)> [head_2|tail_2] = tail [2, 3] iex(6)> head_2 2 iex(7)> tail_2 [3]
  9. defmodule Hello do def world do "Hello World" end def

    world(name) do "Hello #{name}" end end iex(1)> Hello.world "Hello World" iex(2)> Hello.world("Andy") "Hello Andy"
  10. defmodule Hello do def world, do: greeting("World") def world(name), do:

    greeting("Hi", name) defp greeting(salutation \\ "Hello", name) do "#{salutation} #{name}" end end iex(1)> Hello.world "Hello World" iex(2)> Hello.world("Andy") "Hi Andy" iex(3)> Hello.greeting("Andy") ** (UndefinedFunctionError) function Hello.greeting/1 is undefined or private
  11. defmodule Maths do def arithmetic(:add, a, b), do: a +

    b def arithmetic(:subtract, a, b), do: a - b end iex(1)> Maths.arithmetic(:add, 1, 2) 3 iex(2)> Maths.arithmetic(:subtract, 10, 2) 8 iex(2)> Maths.arithmetic(:multiply, 3, 3) ** (FunctionClauseError) no function clause matching…
  12. defmodule MyList do def count([]), do: 0 def count([_ |

    tail]) do 1 + count(tail) end end iex(1)> MyList.count([]) 0 iex(2)> MyList.count([1, 2, 3]) 3
  13. defmodule MyList do def count(list, total \\ 0) def count([],

    total), do: total def count([_ | tail], total) do count(tail, total + 1) end end iex(1)> MyList.count([]) 0 iex(2)> MyList.count([1, 2, 3]) 3
  14. defmodule Guard do def what_is(x) when is_atom(x) do IO.puts "#{x}

    is an atom" end def what_is(x) when is_number(x) and x > 0 do IO.puts "#{x} is a positive number" end def what_is(_), do: IO.puts "Unknown" end iex(1)> Guard.what_is(10) 10 is a positive number iex(2)> Guard.what_is("Andy") Unknown
  15. iex(1)> String.downcase("ANDY") "andy" iex(2)> String.ends_with?("Andy", "y") true iex(3)> Enum.map([1, 2,

    3], fn(x) -> x * x end) [1, 4, 9] iex(4)> Enum.map([1, 2, 3], &(&1 * &1)) [1, 4, 9] iex(5)> Map.has_key?(%{ name: "Andy" }, :name) true
  16. text = " Hi Andy " text = String.downcase(text) text

    = String.strip(text) text = String.reverse(text) => "ydna ih" String.reverse(String.strip(String.downcase(text))) => "ydna ih"
  17. text = " Hi Andy " text |> String.downcase |>

    String.strip |> String.reverse => "ydna ih"
  18. defmodule MyString do @doc ~S""" Converts a string to uppercase

    ## Examples iex> MyString.upcase("andy") "ANDY" """ def upcase(string) do String.upcase(string) end end
  19. defmodule MyStringTest do use ExUnit.Case doctest MyString end $ mix

    test 1 test, 0 failures iex(1)> h MyString.upcase Converts a string to uppercase ## Examples iex> MyString.upcase("andy") "ANDY"
  20. iex(1)> pid = spawn(fn -> IO.puts "Hello World" end) Hello

    World #PID<0.82.0> iex(2)> Process.alive?(pid) false
  21. defmodule Chat do def greet do IO.puts "Hello World" end

    end iex(1)> pid = spawn(Chat, :greet, []) Hello World #PID<0.82.0>
  22. defmodule ChatWorker do def loop do receive do { :greet,

    name } -> IO.puts "Hi #{name}!" loop() end end end iex(1)> pid = spawn(ChatWorker, :loop, []) #PID<0.118.0> iex(2)> Process.alive?(pid) true
  23. defmodule ChatWorker do def loop do receive do { :greet,

    name } -> IO.puts "Hi #{name}!" loop() end end end iex(3)> send pid, { :greet, "Andy" } Hi Andy! iex(4)> Process.alive?(pid) true
  24. defmodule NothingWorker do def loop do receive do { :exit

    } -> IO.puts "Exiting…" _ -> loop() end end end iex(1)> pid = spawn(NothingWorker, :loop, []) iex(2)> send pid, { :covfefe } iex(3)> Process.alive?(pid) true
  25. defmodule NothingWorker do def loop do receive do { :exit

    } -> IO.puts "Exiting…" _ -> loop() end end end iex(4)> send pid, { :exit } Exiting… iex(3)> Process.alive?(pid) false
  26. defmodule Counter do def init(count \\ 0) do loop(count) end

    def loop(count) do receive do { :add, number } -> count = count + number loop(count) { :current, sender } -> send(sender, { :ok, count }) loop(count) end end end
  27. iex(1)> pid = spawn(Counter, :init, []) #PID<0.88.0> iex(2)> send(pid, {:add,

    1}) {:add, 1} iex(3)> send(pid, {:add, 2}) {:add, 2} iex(4)> send(pid, {:current, self()}) {:current, #PID<0.80.0>} iex(5)> flush() {:ok, 3} :ok
  28. OTP

  29. defmodule OTPCounter do use GenServer # Public API def start_link

    do GenServer.start_link(__MODULE__, :ok, []) end # Callbacks def init(:ok) do {:ok, 0} end end initial state
  30. defmodule OTPCounter do # snip… # Public API def current(pid)

    do GenServer.call(pid, :current) end # Callbacks def handle_call(:current, from_pid, state) do {:reply, state, state} end end
  31. defmodule OTPCounter do # snip… # Client API def add(pid,

    number) do GenServer.cast(pid, {:add, number}) end # Callbacks def handle_cast({:add, number}, state) do {:noreply, state + number} end end
  32. # Public API def stop(pid) do GenServer.cast(pid, :stop) end #

    Callbacks def handle_cast(:stop, state) do {:stop, :normal, state} end def terminate(reason, state) do IO.puts "Server stopping with total #{state}" :ok end
  33. iex(1)> {:ok, pid} = OTPCounter.start_link {:ok, #PID<0.94.0>} iex(2)> OTPCounter.current(pid) 0

    iex(3)> OTPCounter.add(pid, 1) :ok iex(4)> OTPCounter.add(pid, 1) :ok iex(5)> OTPCounter.current(pid) 2 iex(6)> OTPCounter.stop(pid) Server stopping with total 2 iex(7)> Process.alive?(pid) false
  34. Process 1 Process 2 Process 3 Process 4 Run Queue

    Current Process Until empty mailbox or 2000 reductions
  35. iex> self() #PID<0.80.0> iex> import Supervisor.Spec Supervisor.Spec iex> c =

    [worker(OTPCounter, [], [])] … iex> {_, sup} = Supervisor.start_link(c, strategy: :one_for_one) {:ok, #PID<0.90.0>} iex> {_, [_, counter]} = Process.info(sup, :links) {:links, [#PID<0.80.0>, #PID<0.91.0>]}
  36. iex> OTPCounter.add(counter, 1) :ok iex> OTPCounter.current(counter) 1 iex> OTPCounter.crash(counter) [error]

    GenServer #PID<0.91.0> terminating… iex> {_, [_, counter]} = Process.info(sup, :links) {:links, [#PID<0.80.0>, #PID<0.95.0>]} iex> OTPCounter.current(counter) 0
  37. Node :foo Core 1 Core n . . . Core

    1 Core n . . . Node :bar msg
  38. $ iex --name [email protected] --cookie s3cr3t iex([email protected])1> Node.connect(:"[email protected]") true iex([email protected])2>

    Node.list [:"[email protected]"] iex([email protected])3> c "chat_worker.exs" [ChatWorker] $ iex --name [email protected] --cookie s3cr3t iex([email protected])1> Node.list [:"[email protected]"] iex([email protected])2> ChatWorker.loop ** (UndefinedFunctionError) function ChatWorker.loop/0 is undefined
  39. $ iex --name [email protected] --cookie s3cr3t iex([email protected])1> Node.connect(:"[email protected]") true iex([email protected])2>

    Node.list [:"[email protected]"] iex([email protected])3> c "chat_worker.exs" [ChatWorker] iex([email protected])3> pid = Node.spawn_link :"[email protected]", ChatWorker, :loop, [] #PID<9137.108.0> iex([email protected])4> send(pid, {:greet, "Andy"}) Hi Andy!
  40. Framework Throughput (req/s) Avg Latency (ms) Phoenix 31,417 3.52 Express

    9,477 10.56 Sinatra 8,334 7.46 Rails 3,452 17.96 https://github.com/mroth/phoenix-showdown/blob/master/RESULTS_v3.md
  41. "I thought of objects being like biological cells or individual

    computers on a network, only able to communicate with messages." - Alan Kay