【问题标题】:Run-once Elixir process一次性 Elixir 流程
【发布时间】:2019-10-23 06:17:30
【问题描述】:

我正在尝试通过调用 genServer 模块“Cache”来创建“Cache warmer”以在应用程序启动时运行一次

我创建了一些代码: GenServer "Cache Warmer",用于在应用程序启动时处理单个异步调用,配置为 [restart: :temporary]。主要思想是在施法后返回{:stop, :normal, state},关闭进程

defmodule TlgmBot.Application do
 ...
     def start(_type, _args) do
     ...
       children = [
       ... some stuff ...
        %{
          id: Services.Cache.CacheWarmer,
          start: {Services.Cache.CacheWarmer, :start_link, [restart: :temporary]},
          type: :supervisor
      }

        %{
          id: Services.Cache.Cache,
          start: {Services.Cache.Cache, :start_link, []},
          type: :supervisor
      },
    end
end
defmodule Services.Cache.CacheWarmer do
 use GenServer

  def start_link(_state \\ []) do
    GenServer.start_link(__MODULE__, [:ok], name: __MODULE__)
  end

  def handle_cast({:warm_up_cache}, state) do
    debug "loading users..."
    load_users()
    debug "done."
    load_mfc()

    {:stop, :normal, state}
  end

  defp load_users() do
    result = RedmineApi.request_rm_users()

    case result do
    {:ok, users} -> Cache.save_users(users)
                    {:ok}
    _            -> {:error}
    end
  end
end

并且进程“缓存预热器”仍在一次又一次地运行

请指出我完成此任务的正确方法或帮助我找出我在这里做错了什么。

也许我应该在 application.start() 中添加几行来在这里调用缓存模块而忘记它?

【问题讨论】:

  • GenServer.handle_continue/2 肯定是要走的路,但总的来说问题是;你为什么要监督根本不打算监督的事情?生成一个未链接的进程。它会按照你的意愿默默地死去。

标签: elixir gen-server


【解决方案1】:

由于您的 Cache Warmer 不使用它的状态,或者一旦它履行了职责就需要存在,我建议您改为在启动应用程序时或在您的 Cache 中的 handle_continue 内部调用一个函数。这将在init 之后发生,以免阻止启动其他孩子。

请参阅:GenServer.handle_continue/2

【讨论】:

    【解决方案2】:

    除了@aleksei-matiushkin 发布的handle_continue/2之外,您还可以在您的监督树中缓存之后添加一个任务:

    MyApp.Cache,
    {Task, &MyApp.Cache.warmup/0}
    

    默认情况下,任务是临时的,这意味着它在崩溃时不会重新启动。请注意,如果缓存进程崩溃,handle_continue/2 将在进程重新启动后再次运行。如果监督策略是:one_for_one,任务将不会再次运行,但对于:rest_for_one:one_for_all 会运行。

    您发布的代码有两个问题:缓存预热器在缓存之前启动,因此转换请求不会找到缓存服务器。它还将孩子列为type: :supervisor,这应该只对主管执行(它不会在这里造成实际的错误,但它可能会在关机、热代码升级等期间导致问题)。

    【讨论】:

    • 谢谢。我想如果缓存进程崩溃,我需要再次运行任务,但我无意更改主管的策略(当前一对一),我应该在缓存模块中使用 handle_continue 选项。
    猜你喜欢
    • 2016-01-14
    • 2016-01-17
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 2016-03-21
    • 2018-05-07
    相关资源
    最近更新 更多