Elixir - Tolerância a Falhas para Adultos - Secot VIII Sorocaba

57
ELIXIR Tolerância a Falhas para Adultos Fabio Akita

Transcript of Elixir - Tolerância a Falhas para Adultos - Secot VIII Sorocaba

ELIXIRTolerância a Falhas para Adultos

Fabio Akita

@akitaonrails@akitaonrails

Rubyconf Brasil 2016 – 23 e 24 de SetembroRubyconf Brasil 2016 – 23 e 24 de Setembro

Rubyconf Brasil 2016 – 23 e 24 de SetembroRubyconf Brasil 2016 – 23 e 24 de Setembro

Rubyconf Brasil 2016 – 23 e 24 de SetembroRubyconf Brasil 2016 – 23 e 24 de Setembro

Chris McCordChris McCord José ValimJosé Valim

Joe Armstrong - EricssonJoe Armstrong - Ericsson

defmodule Teste do def say(name) do IO.puts("Hello #{name}") endend

Teste.say("Fabio")

defmodule Teste do @spec say(String.t) def say(name) when is_string(name) do IO.puts "Hello " <> name endend

Teste.say "Fabio"

OPTIONAL PARENTHESIS

-module(teste).-export([qsort/1]).

qsort([]) -> [];qsort([Pivot|T]) -> qsort([X||X<-T,X =< Pivot]) ++ [Pivot] ++ qsort([X||X<-T,X > Pivot]).

defmodule Teste do def qsort([]), do: [] def qsort([pivot|t]) do qsort(for x <- t, x < pivot, do: x) ++ [pivot] ++ qsort(for x <- t, x >= pivot, do: x) endend

defmodule Teste do def factorial(n) do if n == 0 do 1 else n * factorial(n - 1) end endend

Teste.factorial(10)# => 3628800

defmodule Teste do def factorial(0), do: 1 def factorial(n) do n * factorial(n - 1) endend

Teste.factorial(10)# => 3628800

CALL BY PATTERN

{:ok, result} = Enum.fetch([1, 2, 3, 4], 3)IO.puts result# => 4

registro = {:ok, %{name: "Fabio", last_name: "Akita"}}{:ok, %{name: name}} = registroIO.puts name# => Fabio

registro = %{name: "Fabio", year: 2016, foo: {:ok, [1, 2, 3]}}%{name: name, foo: {:ok, result}} = registroIO.puts Enum.join([name|result], ", ")# => Fabio, 1, 2, 3

%{last_name: name} = registro# => ** (MatchError) no match of right hand side value: ...

PATTERN MATCHING(“Regex for non-String”)

a = 1a = 2IO.puts a# => 2

^a = 3# => ** (MatchError) no match of right hand side value: 3

message = "Hello"IO.puts message <> " World!"# => "Hello World!IO.puts "#{message} World!"# => "Hello World!

{:a, "b", 67, true}[:a, "b", 67, true]%{a: 1, b: 2, c: 3}[a: 1, b: 2, c: 3]# => [{:a, 1}, {:b, 2}, {:c, 3}]

range = (1..100)interval = Enum.slice(range, 30, 10)evens = Enum.filter(interval, fn(n) -> rem(n, 2) == 0 end)multiplied = Enum.map(evens, fn(n) -> n * 10 end)Enum.take(multiplied, 2)

range = (1..100)# => [1, 2, 3, 4 ... 98, 99, 100]interval = Enum.slice(range, 30, 10)# => [31, 32, 33, 34, 35, 36, 37, 38, 39, 40]evens = Enum.filter(interval, fn(n) -> rem(n, 2) == 0 end)# => [32, 34, 36, 38, 40]multiplied = Enum.map(evens, fn(n) -> n * 10 end)# => [320, 340, 360, 380, 400]Enum.take(multiplied, 2)# => [320, 340]

range = (1..100)interval = Enum.slice(range, 30, 10)evens = Enum.filter(interval, fn(n) -> rem(n, 2) == 0 end)multiplied = Enum.map(evens, fn(n) -> n * 10 end)Enum.take(multiplied, 2)

Enum.take( Enum.map( Enum.filter( Enum.slice((1..100), 30, 10), fn(n) -> rem(n, 2) == 0 end ), fn(n) -> n * 10 end ), 2)

range = (1..100)interval = Enum.slice(range, 30, 10)evens = Enum.filter(interval, fn(n) -> rem(n, 2) == 0 end)multiplied = Enum.map(evens, fn(n) -> n * 10 end)Enum.take(multiplied, 2)

(1..100)|> Enum.slice(30, 10)|> Enum.filter(fn(n) -> rem(n, 2) end)|> Enum.map(fn(n) -> n * 10 end)|> Enum.take(2)

(1..100)|> Enum.slice(30, 10)|> Enum.filter(&(rem(&1, 2)))|> Enum.map(&(&1 * 10))|> Enum.take(2)

(1..100)|> Enum.slice(30, 10)|> Enum.filter(fn(n) -> rem(n, 2) end)|> Enum.map(fn(n) -> n * 10 end)|> Enum.take(2)

PIPE OPERATOR|>

function = fn -> IO.puts("Hello from function") end

function.()# => Hello from function

pid = spawn(function)# => Hello from function

Process.alive?(pid)# => falseProcess.alive?(self)# => true

pid = spawn(fn -> receive do {:say, from} -> send(from, "say what?") _ -> Process.exit(self, :normal) endend)

Process.alive?(pid)# => true

send(pid, {:say, self})

receive do message -> IO.puts("Recebido: " <> message)end# => Recebido: say what?

send(pid, "blabla")

Process.alive?(pid)# => false

“PROCESSES”

LightweightIsolatedMessage passingMailboxGarbage Collected

pid = spawn(fn -> ... end)

Process.exit(pid, :kill)

pid = spawn_link(fn -> receive do {:say, from} -> send(from, "say what?") _ -> Process.exit(self, :normal) endend)

send(pid, "blabla")** (EXIT from #PID<0.47.0>) killed

pid = spawn_link(fn -> ... end)

Process.exit(pid, :kill)

pid = spawn_link(fn -> receive do {:say, from} -> send(from, "say what?") _ -> Process.exit(self, :normal) endend)

Process.flag(:trap_exit, true)

send(pid, "blabla")

receive do {:EXIT, _pid, reason} -> IO.puts("Motivo do crash: #{reason}")end# => Motivo do crash: normal

ASYNCHRONOUSEXCEPTIONS(spawn_link, flag, exit)

“GLOBALS”

JavascriptScalaGoClojure...

defmodule Stack do def start_link do Agent.start_link(fn -> [] end, name: __MODULE__) end

def pop do Agent.get_and_update(__MODULE__, fn(state) -> [head|tail] = state {head, tail} end) end

def push(new_value) do Agent.update(__MODULE__, fn(state) -> [new_value|state] end) endend

Stack.start_link

Stack.push "hello"Stack.push "world"

Stack.pop# => worldStack.pop# => hello

Process.list |> Enum.reverse |> Enum.at(0) |> Process.exit(:kill)

Stack.push "foo"# => ** (exit) exited in: GenServer.call(Stack, {:update, ...,5000)# ** (EXIT) no process# (elixir) lib/gen_server.ex:564: GenServer.call/3

defmodule Stack.Supervisor do use Supervisor

def start_link do Supervisor.start_link(__MODULE__, :ok) end

def init(:ok) do children = [ worker(Stack, []) ]

supervise(children, strategy: :one_for_one) endend

Stack.Supervisor.start_link

Stack.push "hello"Stack.push "world"

Stack.pop# => worldStack.pop# => hello

Process.list |> Enum.reverse |> Enum.at(0) |> Process.exit(:kill)

Stack.push "foo"Stack.push "bla"

Stack.pop# => blaStack.pop# => foo

Stack.Supervisor.start_link

Process.list |> Enum.reverse |> Enum.at(0) |> Process.exit(:kill)

“YOCTO” SERVICES(micro > nano > pico > femto > atto > zepto > yocto>

APRENDENDO

OBRIGADO!Perguntas?

@akitaonrails