elixirmemoizationelixir-mix

using melpon/memoize in elixir mix task


I am using melpon/memoize for cache in my phoenix aplication. It is working very well in runtime.

However, I have a few mix tasks in my application, which I execute sparingly. Now these tasks eventually call a memoized function, for example:

defmodule Mix.Tasks.MyTask do
  use Mix.Task
  alias MemoizedModule
  require Logger;
  use Memoize

  def run(_) do
    MemoizedModule.get_value()
  end
end

defmodule MemoizedModule do
  use Memoize
  defmemo get_value() do
    1
  end
end

and it crashes with:

/opt/app # mix my_task
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: no persistent term stored with this key

    :persistent_term.get(:memoize_cache_strategy)
    (memoize 1.4.0) lib/memoize/config.ex:29: Memoize.Config.cache_strategy/0
    (memoize 1.4.0) lib/memoize/cache.ex:11: Memoize.Cache.tab/1
    (memoize 1.4.0) lib/memoize/cache.ex:103: Memoize.Cache.do_get_or_run/3
    (mix 1.12.3) lib/mix/task.ex:394: anonymous fn/3 in Mix.Task.run_task/3
    (mix 1.12.3) lib/mix/cli.ex:84: Mix.CLI.run_task/2
    (elixir 1.12.3) lib/code.ex:1261: Code.require_file/2

If I try to execute the code inside IEx, it works as expected:

/opt/app # iex -S mix
Interactive Elixir (1.12.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Mix.Tasks.MyTask.run()
1

I know it has something to do with some initialization that is not done in mix tasks, but I can´t figure out what it is.


Solution

  • We need to start applications explicitly in mix tasks.

    Codes are loaded, but applications are not started when running mix commands.

    Mix does not automatically start our application or any of its dependencies ... Ref

    So we need to start the it explicitly:

    def run(_) do
      {:ok, _} = Application.ensure_all_started(:memoize)
    
      MemoizedModule.get_value()
    end
    

    You may need to change :memoize to :my_otp_app if you need other initialization tasks in the app.

    Why does it work inside iex -S mix?

    That's because iex -S mix [run] has started your application for you.