Как использовать Task.await с GenServer?

Я пытаюсь выяснить, как запустить genserver и дождаться результата, пока он не закончится.

Как заставить сервер вернуть результат при выходе?

как например:

defmodule DistanceMatrix do
  use GenServer

  def start id do
    GenServer.start(__MODULE__, id)
  end

  def load() do
    GenServer.cast({:load})
  end

  def handle_cast({:load}, state) do
    # start long process operation
    long_process
    {:noreply, state}
  end

  def long_process do
    :timer.sleep 2000
    %{result: "Process result.."}
  end

end 


results= ids
|> Enum.map(fn id -> DistanceMatrix.start(id) end)
|> Enum.map(&Task.await/1)
|> Enum.map(fn({:ok, result}) -> 
   result
   end)

Итак, как бы я подождал и получил результат?

1 ответ

Решение

Вот один из способов: в :loadcast, вернуть результат long_process как новое состояние. Затем добавьте call который просто возвращает текущее состояние (по имени :get ниже). Поскольку GenServer обрабатывает сообщения последовательно в порядке их отправки, :get звонок будет заблокирован до предыдущего :load завершено.

defmodule DistanceMatrix do
  use GenServer

  def start(id) do
    GenServer.start(__MODULE__, id)
  end

  def load(pid) do
    GenServer.cast(pid, {:load})
    pid
  end

  def await(pid), do: GenServer.call(pid, :get)

  def init(id), do: {:ok, id}

  def handle_call(:get, _, state), do: {:reply, state, state}

  def handle_cast({:load}, _state) do
    {:noreply, long_process()}
  end

  def long_process do
    :timer.sleep(2000)
    %{result: "Process result.."}
  end
end

1..10
|> Enum.map(fn id ->
  {:ok, pid} = DistanceMatrix.start(id)
  pid
end)
|> Enum.map(&DistanceMatrix.load/1)
|> Enum.map(&DistanceMatrix.await/1)
|> Enum.map(fn result ->
  IO.inspect(result)
end)

Выход:

%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}

Программа занимает чуть более 2 секунд, как и ожидалось.

Другие вопросы по тегам