Search code examples
elixirgen-server

Run-once Elixir process


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?


Solution

  • 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.