handle_info 或 handle_call 期间的 Genserver 状态更改
Posted
技术标签:
【中文标题】handle_info 或 handle_call 期间的 Genserver 状态更改【英文标题】:Genserver state change during handle_info or handle_call 【发布时间】: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
【问题讨论】:
【参考方案1】:传入的消息正在被放入进程邮箱,并且在进程从之前的handle_***
返回之前不会被处理。你冒着溢出进程邮箱的风险,不要错过一些消息。
为防止这种情况发生,Elixir Core 团队明确创建了GenStage
以应对压力。
【讨论】:
谢谢@mudasobwa 我刚刚开始研究 GenStage 以应对背压。非常感谢您的意见。以上是关于handle_info 或 handle_call 期间的 Genserver 状态更改的主要内容,如果未能解决你的问题,请参考以下文章
Erlang / OTP App 的 handle_info 没有收到 nodedown, _, _ 或 nodedown, _ 消息