一次运行的Elixir过程

时间:2019-06-07 18:14:40

标签: elixir gen-server

我正在尝试通过调用genServer模块“缓存”来创建“缓存预热器”以在应用程序启动时运行ONCE

我创建了一些代码: 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

并且进程“ Cache warmer”仍然一次又一次地运行

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

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

2 个答案:

答案 0 :(得分:3)

由于您的缓存器不使用其状态或一旦执行任务就需要存在,因此建议您在启动应用程序时或在缓存的handle_continue内部调用函数。这将发生在init之后,以免阻止其他孩子的成长。

请参阅:GenServer.handle_continue/2

答案 1 :(得分:2)

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

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

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

您发布的代码有两个问题:缓存预热在缓存之前开始开始,因此强制转换请求将找不到缓存服务器。它还将子级列为type: :supervisor,只应对主管执行此操作(它不会在此处引起实际的错误,但可能会在关机,热代码升级等过程中引起问题)。