我正在尝试通过调用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()中添加几行来在这里调用缓存模块,然后忘记它?
答案 0 :(得分:3)
由于您的缓存器不使用其状态或一旦执行任务就需要存在,因此建议您在启动应用程序时或在缓存的handle_continue
内部调用函数。这将发生在init
之后,以免阻止其他孩子的成长。
答案 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
,只应对主管执行此操作(它不会在此处引起实际的错误,但可能会在关机,热代码升级等过程中引起问题)。