I have some problems using mnesia
inside a Mix task. I saw this post but the solution did not seem to work for me. I used :mnesia.wait_for_tables([:my_table], 10_000)
and still data does not persist. This ONLY happens in a mix task. If I run the same queries in an iex
session, everything works.
Inside iex
I can do this:
iex> :mnesia.transaction(fn -> :mnesia.write({:my_table, "x", "hello"}) end)
{:atomic, :ok}
then I can ctrl-c exit, start iex
again and run this:
iex> :mnesia.transaction(fn -> :mnesia.read({:responses, "x"}) end)
{:atomic, [{:responses, "x", "hello", 123}]}
and it works: mnesia remembers the value!
However, when I do the same inside mix task, it does not seem to remember. It can read what I write in iex
however:
def run(args) do
{:ok, _} = Application.ensure_all_started(:my_app)
x = :mnesia.transaction(fn -> :mnesia.read({:my_table, "x"}) end)
IO.inspect(x) # <-- {:atomic, [{:responses, "x", "hello", 123}]}
end
but if I do something like this :
def run(args) do
{:ok, _} = Application.ensure_all_started(:my_app)
w = :mnesia.transaction(fn -> :mnesia.write({:my_table, "y", "hello"}) end)
IO.inspect(w) # <--- {:atomic, :ok}
y = :mnesia.transaction(fn -> :mnesia.read({:my_table, "y"}) end)
IO.inspect(y) # <---- {:atomic, [{:responses, "y", "hello2", 123}]}
end
and then I comment out the writing so it tries to read what I wrote previously, it does not work:
def run(args) do
{:ok, _} = Application.ensure_all_started(:my_app)
# w = :mnesia.transaction(fn -> :mnesia.write({:my_table, "y", "hello"}) end)
# IO.inspect(w) # <--- {:atomic, :ok}
y = :mnesia.transaction(fn -> :mnesia.read({:my_table, "y"}) end)
IO.inspect(y) # <---- {:atomic, []}
end
When I run mix my_task
the 2nd time, it does not remember the previously set y
. It can read values that were written from inside iex
, so this is maybe a clue.
I am hoping someone can show me what I am missing. I am sorry this is complicated to explain but I will try to share how I have my application starting:
Inside mix.exs
:
def application do
[
extra_applications: [:logger],
mod: {MyApp.Application, []},
included_applications: [:mnesia],
start_phases: [init: []]
]
end
(I think this start_phases
is correct?)
Then inside application.ex
:
def start_phase(:init, :normal, _) do
MyApp.InitMnesia.setup()
end
Then inside InitMnesia
:
defmodule InitMnesia do
def setup() do
Logger.info("Setting up mnesia...")
:mnesia.start()
case schema_exists?() do
true ->
{:ok, :already_created}
false ->
:mnesia.stop()
:mnesia.create_schema([node()])
:mnesia.start()
end
case table_exists?(:my_table) do
true ->
{:ok, :already_created}
false ->
:mnesia.create_table(
:my_table,
attributes: [:url, :response],
disc_copies: [node()]
)
end
:mnesia.wait_for_tables([:my_table], 10_000)
end
def create_schema() do
case schema_exists?() do
true ->
{:ok, :already_created}
false ->
:mnesia.stop()
:mnesia.create_schema([node()])
:mnesia.start()
end
end
def schema_exists?() do
:mnesia.table_info(:schema, :disc_copies) != []
end
def table_exists?(table_name) do
Enum.member?(:mnesia.system_info(:tables), table_name)
end
end