【问题标题】:Genserver state change during handle_info or handle_callhandle_info 或 handle_call 期间的 Genserver 状态更改
【发布时间】:2019-01-03 11:38:06
【问题描述】:

假设我有一个简单的 genserver,它维护一个简单的 :queue 作为它的状态。使用 handle_cast 不断添加项目。每 5 秒我使用 Process.send_after 处理队列。该调用通过调用当前状态的 handle_info 来处理。队列被处理并清空,然后应用一个新的空队列作为 genserver 的当前状态。

我的问题是: 在处理队列时调用进入 genserver 会发生什么?由于我将一个新的空队列返回到 handle_info {:noreply, :queue.new} 会覆盖在我处理队列时添加的项目吗?或者 genserver 是否会自己排队,然后在 handle_info 完成后允许完成?
基本上我担心在handle_info 期间丢失物品。

代码:

    defmodule TcpClient.Queue do
  use GenServer
  require Logger

  def start_link do
    queue = :queue.new()
    GenServer.start_link(__MODULE__, queue, name: {:global, :tcp_queue})
  end

  def init(queue) do
    Logger.debug("Starting up Queue")
    schedule_work()
    {:ok, queue}
  end

  def enqueue(msg) do
    Logger.debug("Item Added")
    GenServer.cast(whereis(), {:enqueue, msg})
  end

  defp schedule_work() do
    Process.send_after(self(), :work, 1 * 1 * 300)
  end

  def handle_cast({:enqueue, msg}, state) do
    {:noreply, :queue.in(msg, state)}
  end

  def handle_info(:work, queue) do
    case :queue.is_empty(queue) do
      true ->
        Logger.debug("No items to Process")
        nil

      false ->
        Logger.debug("Processing Queue")

        :queue.to_list(queue)
        |> Enum.map(&TcpClient.Repo.add_message(&1))

        queue = :queue.new()
    end

    schedule_work()
    {:noreply, queue}
  end

  def whereis() do
    :global.whereis_name(:tcp_queue)
  end
end

【问题讨论】:

    标签: elixir gen-server


    【解决方案1】:

    传入的消息正在被放入进程邮箱,并且在进程从之前的handle_*** 返回之前不会被处理。你冒着溢出进程邮箱的风险,不要错过一些消息。

    为防止这种情况发生,Elixir Core 团队明确创建了GenStage 以应对压力。

    【讨论】:

    • 谢谢@mudasobwa 我刚刚开始研究 GenStage 以应对背压。非常感谢您的意见。
    猜你喜欢
    • 2019-12-17
    • 2020-08-18
    • 2019-03-27
    • 2017-09-29
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    相关资源
    最近更新 更多