运行-一次 Elixir 进程
Run-once Elixir process
我试图在应用程序启动时通过调用 genServer 模块 "Cache"
创建 "Cache warmer" 到 运行 一次
我创建了一些代码:
GenServer "Cache Warmer",用于处理应用程序启动时的单个异步调用,配置为[restart::temporary]。主要思想是 return {: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() 中添加几行来调用缓存模块并忘记它?
由于您的 Cache Warmer 不使用它的状态或者一旦它履行了它的职责就不需要存在,我建议您在启动您的应用程序时或在您的 handle_continue
内部调用一个函数缓存。这会发生 post init
以免阻止启动其他 children.
除了handle_continue/2
,由@aleksei-matiushkin 发布,你还可以在你的监督树缓存 之后有一个任务:
MyApp.Cache,
{Task, &MyApp.Cache.warmup/0}
默认情况下任务是临时的,这意味着它不会在崩溃时重新启动。请注意,如果缓存进程崩溃,handle_continue/2 将在进程重新启动后再次 运行。如果监督策略为 :one_for_one
,则任务不会再次 运行,但会针对 :rest_for_one
和 :one_for_all
。
您发布的代码有两个问题:缓存预热器在缓存之前启动,因此转换请求找不到缓存服务器。它还将子项列为 type: :supervisor
,这应该只针对主管(它不会在这里导致实际错误,但它可能会在关机、热代码升级等期间导致问题)。
我试图在应用程序启动时通过调用 genServer 模块 "Cache"
创建 "Cache warmer" 到 运行 一次我创建了一些代码: GenServer "Cache Warmer",用于处理应用程序启动时的单个异步调用,配置为[restart::temporary]。主要思想是 return {: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() 中添加几行来调用缓存模块并忘记它?
由于您的 Cache Warmer 不使用它的状态或者一旦它履行了它的职责就不需要存在,我建议您在启动您的应用程序时或在您的 handle_continue
内部调用一个函数缓存。这会发生 post init
以免阻止启动其他 children.
除了handle_continue/2
,由@aleksei-matiushkin 发布,你还可以在你的监督树缓存 之后有一个任务:
MyApp.Cache,
{Task, &MyApp.Cache.warmup/0}
默认情况下任务是临时的,这意味着它不会在崩溃时重新启动。请注意,如果缓存进程崩溃,handle_continue/2 将在进程重新启动后再次 运行。如果监督策略为 :one_for_one
,则任务不会再次 运行,但会针对 :rest_for_one
和 :one_for_all
。
您发布的代码有两个问题:缓存预热器在缓存之前启动,因此转换请求找不到缓存服务器。它还将子项列为 type: :supervisor
,这应该只针对主管(它不会在这里导致实际错误,但它可能会在关机、热代码升级等期间导致问题)。