Разделение состояния между процессами с использованием агентов в Elixir Phoenix - PullRequest
0 голосов
/ 13 марта 2020

У меня есть одна конечная точка HTTP, которая создает карту и сохраняет ее с помощью агента.

Я хочу получить доступ к этой карте, когда я достигаю другой конечной точки. но когда я пытаюсь получить данные от Агента, он возвращается пустым.

Может ли кто-нибудь подтвердить, является ли это действительным сценарием использования Агентов? Если да, то что мне не хватает?

Код:

defmodule BoardState do
  use Agent

  def start_link do
    Agent.start_link(fn -> %{} end, name: __MODULE__)
  end

  def add(game_id, board) do
    Agent.update(__MODULE__, fn state ->
      Map.put(state, game_id, board)
    end)
  end

  def reset do
    Agent.update(__MODULE__, fn _state -> %{} end)
  end

  def get(game_id) do
    Agent.get(__MODULE__, fn state ->
      Map.get(state, game_id)
    end)
  end

  def getKeys() do
    Agent.get(__MODULE__, fn state ->
      Map.keys(state)
    end)
  end

  def name() do
    Agent.agent()
  end
end

Код, с которого запускается агент

`defmodule TicTacToe.Application do
  use Application

  def start(_type, _args) do
    children = [
      TicTacToeWeb.Endpoint
    ]

    **BoardState.start_link()**

    opts = [strategy: :one_for_one, name: TicTacToe.Supervisor]
    Supervisor.start_link(children, opts)
  end

  def config_change(changed, _new, removed) do
    TicTacToeWeb.Endpoint.config_change(changed, removed)
    :ok
  end
end 

Я также пробовал это с Genserver, но когда Я достиг 2-й точки, я не могу получить данные, сохраненные в 1-ой конечной точке

Ответы [ 2 ]

0 голосов
/ 16 марта 2020

Я проверял ваш код из этого репозитория https://github.com/sayali-kotkar/tic_tac_toe на Elixir 1.9. Ваш код выглядит приемлемым. Это работает для меня, или я неправильно понимаю проблему.

1-й запрос:

curl -X POST localhost:4000/game

1-й ответ:

{
   "board":{
      "Cell(1, 1)":"empty",
      "Cell(2, 1)":"empty",
      "Cell(3, 1)":"empty",
      "Cell(1, 2)":"empty",
      "Cell(2, 2)":"empty",
      "Cell(3, 2)":"empty",
      "Cell(1, 3)":"empty",
      "Cell(2, 3)":"empty",
      "Cell(3, 3)":"empty"
   },
   "game_id":67,
   "status":"success"
}

2-й запрос:

curl -X PUT localhost:4000/game/67 \
--header "Content-Type:application/json" \
--data '{"player_id":0, "row": 1, "column": 2}'

2-й ответ:

{
   "board":{
      "Cell(1, 1)":"empty",
      "Cell(2, 1)":"empty",
      "Cell(3, 1)":"empty",
      "Cell(1, 2)":0,
      "Cell(2, 2)":"empty",
      "Cell(3, 2)":"empty",
      "Cell(1, 3)":"empty",
      "Cell(2, 3)":"empty",
      "Cell(3, 3)":"empty"
   },
   "game_id":67,
   "status":"success"
}
0 голосов
/ 13 марта 2020

Я взял ваш код для модуля BoardState почти дословно, за исключением того, что я изменил start_link, чтобы он лучше работал с Supervisor API:

defmodule BoardState do
  ...

  def start_link(_) do
    Agent.start_link(fn -> %{} end, name: __MODULE__)
  end

  ...
end

Я добавил BoardState к своему дерево наблюдения:

defmodule Test.Application do
  ...

  def start(_type, _args) do
    children = [
      TestWeb.Endpoint,
      # Notice I'm putting BoardState under a supervisor here.
      # In your case, you linked it to the process performing the startup,
      # which is a different thing.
      BoardState
    ]

    opts = [strategy: :one_for_one, name: Test.Supervisor]
    Supervisor.start_link(children, opts)
  end

  ...
end

Затем я добавил простой контроллер для его проверки:

defmodule TestWeb.PageController do
  use TestWeb, :controller

  def put(conn, params) do
    BoardState.add(params["key"], params["value"])
    Plug.Conn.resp(conn, 200, "OK\n")
  end

  def get(conn, params) do
    value = BoardState.get(params["key"])
    Plug.Conn.resp(conn, 200, "#{value}\n")
  end
end

И пару маршрутов для этого:

defmodule TestWeb.Router do
  ...
  scope "/", TestWeb do
    ...
    get "/put/:key/:value", PageController, :put
    get "/get/:key", PageController, :get
  end
end

С этим похоже, что он работает, как и ожидалось, помня данные, отправленные на него:

rindr:test yapee$ curl localhost:4000/put/hello/world
OK
rindr:test yapee$ curl localhost:4000/get/hello
world

Я надеюсь, что вы можете отладить свою проблему с помощью этих фрагментов. Я думаю, что ваша проблема может быть связана с тем, что вы на самом деле не ставите свой BoardState под надзор, а случайным образом start_linking вместо него.

...