Reputation: 119
I'm trying to create "Cache warmer" to run ONCE at the application startup, by calling genServer module "Cache"
I've created some code: GenServer "Cache Warmer", which is used to handle a single async call on application startup, configured with [restart: :temporary]. The main idea is return {:stop, :normal, state} after cast, to shut down the process
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
And process "Cache warmer" still running again and again
Please, point me to correct way to complete this task or help me figure out what am i doing wrong here.
Maybe i should add couple of lines in application.start() to call cache module here and forget about it?
Upvotes: 1
Views: 760
Reputation: 51439
Besides handle_continue/2
, posted by @aleksei-matiushkin, you can also have a Task in your supervision tree after the cache:
MyApp.Cache,
{Task, &MyApp.Cache.warmup/0}
A Task is temporary by default, which means it won't be restarted if it crashes. Note though if the cache process crashes, handle_continue/2 will run again once the process restarts. The task won't run again if the supervision strategy is :one_for_one
, but it will for :rest_for_one
and :one_for_all
.
The code you posted has two issues: the cache warmer is starting before the cache, therefore the cast request won't find the cache server. It is also listing the children as type: :supervisor
, that should be done only for supervisors (it won't cause an actual bug here but it may cause problem during shutdown, hot code upgrades, etc).
Upvotes: 6
Reputation: 64
Since your Cache Warmer doesn't use its state or need to exist once it has performed its duty, I would recommend you instead call a function either when starting your application or internally in a handle_continue
in your Cache. This would happen post init
so as not to block starting other children.
See: GenServer.handle_continue/2
.
Upvotes: 4