Elixir:如果服务器重启,如何保持 OTP 队列?

big*_*ato 3 elixir erlang-otp phoenix-framework

我正在使用 OTP 来管理事件队列:

defmodule ParrotApi.MatchingSupervisor do
  use Supervisor

  ## Callbacks

  def start_link() do
    Supervisor.start_link(__MODULE__, [])
  end

  def init(_) do
    children = [
      worker(ParrotApi.MatchingServer, []), # TODO: State is gone if this crashes

      # Supervise connections
      supervisor(Registry, [:unique, :connection_registry]),
      supervisor(ParrotApi.ConnectionSupervisor, []),
    ]

    supervise(children, strategy: :one_for_one)
  end
end
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果服务器重新启动,我的队列会发生什么?重新启动后我需要它继续存在。据我所知,它存储在内存中,因此如果服务器重新启动,它就会被擦除。

Ste*_*len 5

我创建了一个单独的代理来跟踪 GenServer 中的状态。Agent 非常简单,有一个 API 来更新状态,并根据请求获取它。

我创建reply(state, result)noreply(state)在GenServer功能,并呼吁他们在的结束handle_callhandle_casthandle_info功能。

replyno_reply功能把state在代理,然后返回{:no_reply, state}{:reply, result, state}元组。我还在终止时更新代理。

当服务器重新启动时,我检查它是否重新启动,如果是,则从 genserversinit回调中的代理中提取状态。我只是检查代理。如果它没有数据,我知道是一个原始的启动。

这里的想法是代理是一个非常简单的价值存储。它非常简单,不太可能失败。

不过,您应该小心使用这种方法。重启策略背后的想法是 GenServer 以其初始状态重启。如果您的 GenServer 由于其状态问题而重新启动,它可能会进入持续重新启动状态。

  • 不,我只是在解决您的 GenServer 重新启动的问题。如果您需要处理应用程序启动,您可以使用数据库或 erlang 的`DETS` 模块。在这种情况下,您可能不需要代理,您可以将上面示例中对 Agent.put 的调用替换为将数据保存在磁盘上的调用。或者,如果您有一个多节点设计,我想您会使用另一个节点来缓存数据。 (2认同)