Similar to TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had a SRE team at - Creating a stealing points game server with elixir
fog or: How I Learned to Stop Worrying and Love the CloudWesley Beary
Similar to TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had a SRE team at - Creating a stealing points game server with elixir (20)
22. defmodule ExStealerGame do
use Application
def start(_type, _args) do
IO.puts "STARTING THE APPLICATION"
ExStealerGame.Supervisor.start_link
end
end
Starting Point
29. defmodule ExStealerGame.Supervisor do
use Supervisor
…
def init(_) do
children = [
worker(Task, [Server, :start_server, []]),
worker(Match, [])]
supervise children, strategy: :one_for_one
end
end
The Supervisor
30. Keeping State
- Elixir is Immutable
- Processes are used to keep state
- Processes sends and receives messages to
each other to request to receive/set this state
35. defmodule ExStealerGame.Server do
def start_server() do
{:ok, socket} = :gen_tcp.listen(@port, [some_options])
accept_connection(socket)
end
end
Starting the Server
37. defmodule ExStealerGame.Server do
…
defp accept_connection(socket) do
{:ok, client} = :gen_tcp.accept(socket)
handle_player_join(client) # keep player with Agent and send msg to client
{:ok, pid} = Task.start(fn -> match_loop(client) end)
:gen_tcp.controlling_process(client, pid)
accept_connection(socket) # recursively keeps open to new connections
end
end
Connecting to Clients
38. defmodule ExStealerGame.Server do
…
defp match_loop(client) do
client
|> read_client() #wait for client’s message and receive it
|> handle_match_message(client)
match_loop(client) #again, recursively, keeps the game’s match running
end
end
The Game Loop
40. defmodule ExStealerGame.Server do
defp handle_match_message("quit", client) do
quit_player(client)
end
defp handle_match_message(message, client) do
...
end
end
Quitting the Game
41. defmodule ExStealerGame.Server do
defp quit_player(client) do
IO.puts "PLAYER QUITTING"
Match.get_player(client)
|> Match.remove_player
send_score_to_clients() # send message to clients with players list and score
Process.exit(self(), :kill) # kills current process, along with the conection
end
end
Quitting the Game
42. defmodule ExStealerGame.Server do
defp handle_match_message(message, client) do
case Integer.parse(message) do
{target_id, _} ->
Match.get_player(client).id
|> Match.execute_steal(target_id)
Match.get_winners
|> handle_match_state
:error -> send_score_to_clients()
end
end
end
Stealing Points
43. defmodule ExStealerGame.Server do
defp handle_match_state([]) do
send_score_to_clients()
end
defp handle_match_state(winners) do
...
end
end
Checking if there is a winner
44. defmodule ExStealerGame.Server do
defp handle_match_state(winners) do
Match.get_players
|> Enum.each(fn(player) ->
"<End of Match Message>"
|> send_to_client(player.client_pid)
end)
:timer.sleep 2000
Match.restart_match
send_score_to_clients
end
end
Checking if there is a winner
Elixir é uma linguagem que possui diversas características do paradigma funcional.
IMUTABILIDADE, FIRST CLASS FUNCTIONS, PATTERN MATCHING, e etc
Erlang foi construído para isso.
Com um conceito chamado SUPERVISOR, que trata de reiniciar pedaços do sistema quando algo da errado, Erlang te entrega uma arquitetura para lidar com isso.
Seja o Erlang em si ou Elixir, empresas como Whatsapp, Facebook e Discord
utilizam em aplicações de alta demanda, milhões de conexões ao mesmo tempo e etc.
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos
Vou iniciar pelas 2 structs que defini no projeto, por serem os pontos mais simples.
Em elixir, para criarmos uma estrutura pré definida de dados, nós utilizamos essa syntax “defstruct” dentro de um módulo.
O nome da Struct será o mesmo nome desse módulo
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos
Nessa aplicação, utilizei da abstração Agent para gerenciar estado.
Agent é uma abstração do Elixir para simplificar esse uso de estado mantido em processos