Elixir游戏服设计三

玩家进程用gen_server来建模,我不直接使用 use GenServer, 而是使用exactor,该库能够去掉反锁的接口定义。html

咱们新建一个 player_server_manager app吧, 使用 mix new player_server_manager --sup, 会给咱们增长sup。而后在mix.exs里增长exactor的依赖以下:服务器

  defp deps do
    [{:exactor, "~> 2.2"}]
  end

跑 mix deps.get,成功了依赖就准备好了。app

默认生成的player_server_manager.exsocket

defmodule PlayerServerManager do
  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      # Define workers and child supervisors to be supervised
      # worker(PlayerServerManager.Worker, [arg1, arg2, arg3]),
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: PlayerServerManager.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

玩家进程就叫player_server吧。把它改为我须要的。分布式

defmodule PlayerServerManager do
  use Application

  # See http://elixir-lang.org/docs/stable/elixir/Application.html
  # for more information on OTP Applications
  def start(_type, _args) do
    import Supervisor.Spec, warn: false

    children = [
      # Define workers and child supervisors to be supervised
      worker(PlayerServer, [], restart: :temporary),
    ]

    # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :simple_one_for_one, name: PlayerServerManager.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

由于玩家进程是动态建立的,所以采用simple_one_for_one, 同时我不须要默认传参数,还有我不须要重启。测试

好了如今让咱们编写PlayerServer模块(如今是简单的,并且我还未知有什么须要调整的,后续随着服务器设计而演化吧)。spa

让咱们先增长个查询钻石的接口吧。设计

defmodule PlayerServer do

    use ExActor.GenServer

    defstart start_link(player), do: initial_state(%{player: player, socket: nil})
    defcall gem, state: state, do: reply(state.player.base_info.gem)
end

咱们在PlayerServerManager里增长启动接口以下rest

 def start_player_server(%Player{} = player) do
    Supervisor.start_child(PlayerServerManager.Supervisor, [player])
  end

在player_server_manager_test.exs里增长测试代码code

defmodule PlayerServerManagerTest do
  use ExUnit.Case
  doctest PlayerServerManager
  
  setup do
    Application.stop(:player_server_manager)
    :ok = Application.start(:player_server_manager)
  end

  setup do
      player = Player.new(0)
      {:ok, player: player}
  end
  test "start player_server", %{player: player} do
    assert {:ok, pid} = PlayerServerManager.start_player_server(player)
    assert  PlayerServer.gem(pid) == 0
  end
end

测试经过。

写到这里发现以前Player和BaseInfo @behavior 实际上应该为@hehaviour, 既然以前没报错,我就把它去掉了,测试依然经过。说明其实可能只须要

defdelegate。

好了,这一章就到这。遗留的问题有,咱们一般须要给玩家进程一个名字,而不是经过pid,若是是单节点的话, local 注册已经足够,若是是跨服访问,咱们须要一个分布式的注册机制(实际上分布式注册机制容易有坑,如无必要,千万别)。好比gporc,好比syn。 前者比较有名,我之前在erlang用过,以前有碰到莫名奇妙的问题。因此下章试试syn吧。

相关文章
相关标签/搜索