上回说用Registry 做本地注册(跨服可以用syn,只是稍微麻烦点,需要模拟global注册机制,写个封装模块)。
修改game_server 项目的mix.exs, 增加应用启动
def application do [ extra_applications: [:logger], mod: {GameServer, []} ] end
修改game_server.ex 实现,如下应用的监控树监管PlayerRegistry进程和PlayerSupervisor。这里可以考虑 :one_for_rest 选项,因为PlayerRegistry 挂了, 恐怕系统都玩不下去。
defmodule GameServer do use Application def start(_type, _args) do children = [ {Registry, keys: :unique, name: PlayerRegistry}, PlayerSupervisor ] Supervisor.start_link(children, strategy: :one_for_one) end end
修改player_server.ex
defmodule PlayerServer do use GenServer, restart: :temporary, start: {__MODULE__, :start_link, []} def start_link(player) do GenServer.start_link(__MODULE__, player, name: register_name(player)) end def init(player) do {:ok, player} end def register_name(%{} = player), do: register_name(player |> Player.get_id) def register_name(id), do: {:via, Registry, {PlayerRegistry, id}} end
修改测试
defmodule PlayerSupervisorTest do use ExUnit.Case doctest PlayerSupervisor setup do Application.stop(GameServer) Application.start(GameServer) %{} end test "测试PlayerSupervisor启动PlayerServer" do assert {:ok, p1} = PlayerSupervisor.start_player(Player.init |> Player.set_id(1)) assert {:ok, p2} = PlayerSupervisor.start_player(Player.init |> Player.set_id(2)) assert [{^p1, nil}] = Registry.lookup(PlayerRegistry, 1) assert [{^p2, nil}] = Registry.lookup(PlayerRegistry, 2) end end