Argument error on :ets.lookup(:tzdata_current_release, :release_version) when running inside migration
Asked Answered
S

1

7

I have this piece of code:

case Timex.Timezone.get(data) do
  {:error, _} = error ->
    error

  data ->
    {:ok, data}
end

to put timezones that are saved in the database into a struct.

Well when running a migration that gets some data through an Ecto Query I get this error:

** (ArgumentError) argument error
    (stdlib) :ets.lookup(:tzdata_current_release, :release_version)
    lib/tzdata/release_reader.ex:47: Tzdata.ReleaseReader.current_release_from_table/0
    lib/tzdata/release_reader.ex:14: Tzdata.ReleaseReader.simple_lookup/1
    lib/tzdata/release_reader.ex:7: Tzdata.ReleaseReader.zone_and_link_list/0
    lib/tzdata.ex:40: Tzdata.zone_exists?/1
    lib/timezone/timezone.ex:152: Timex.Timezone.name_of/1
    lib/timezone/timezone.ex:180: Timex.Timezone.get/2
    lib/common/ecto/timezone.ex:27: Common.Ecto.Timezone.load/1
    (ecto) lib/ecto/type.ex:661: Ecto.Type.process_loaders/3
    (ecto) lib/ecto/schema.ex:1490: Ecto.Schema.load!/5
    (ecto) lib/ecto/schema.ex:1442: Ecto.Schema.safe_load_zip/4
    (ecto) lib/ecto/schema.ex:1443: Ecto.Schema.safe_load_zip/4
    (ecto) lib/ecto/schema.ex:1430: Ecto.Schema.__safe_load__/6
    (ecto) lib/ecto/repo/queryable.ex:282: Ecto.Repo.Queryable.process_source/6
    (ecto) lib/ecto/repo/queryable.ex:170: Ecto.Repo.Queryable.preprocess/5
    (postgrex) lib/postgrex/query.ex:77: DBConnection.Query.Postgrex.Query.decode_map/3
    (postgrex) lib/postgrex/query.ex:64: DBConnection.Query.Postgrex.Query.decode/3
    (db_connection) lib/db_connection.ex:1019: DBConnection.decode/6
    (ecto) lib/ecto/adapters/postgres/connection.ex:73: Ecto.Adapters.Postgres.Connection.prepare_execute/5
    (ecto) lib/ecto/adapters/sql.ex:256: Ecto.Adapters.SQL.sql_call/6

Which has that code in the stack trace and doing some Inspects can verify that that's indeed the call that triggers the error, although doing:

iex(1)> Timex.Timezone.get("America/Los_Angeles")
#<TimezoneInfo(America/Los_Angeles - PDT (-07:00:00))>

In iex -S mix works.

Sisile answered 10/7, 2018 at 18:33 Comment(0)
B
9

This error happens because Timex needs to be started to function. This is normally done automatically if you add it to your mix.exs dependencies at application startup. However, in mix tasks you have to manually select which applications to start. In your custom mix tasks, you can make sure an application is started via Application.ensure_all_started(:timex).

In your ecto.migrate case, we don't have access to the actual mix task, so we need to be a bit more creative by using mix aliases in your mix.exs file:

  def project do
    [
      ...
      aliases: aliases(),
      ...
    ] 
  end


  defp aliases do
    [
      "ecto.migrate_s": ["ecto.migrate.startup", "ecto.migrate"],
    ]
  end

And a Task ecto.migrate.startup for our Application.ensure_all_started(:timex)

defmodule Mix.Tasks.Ecto.Migrate.Startup do
  use Mix.Task

  def run(args) do
    Mix.shell.info("Starting apps required for ecto.migrate...")
    Application.ensure_all_started(:timex)
  end
end

Now you should be able to run mix ecto.migrate_s which first starts timex and then runs your migrations. (This is not a perfectly clean solution, but I'm not aware of alternatives right now)

Behead answered 10/7, 2018 at 19:34 Comment(2)
I'm pretty sure the alias could be defined as "ecto.migrate": ["run ecto.migrate.startup", "run ecto.migrate"] to effectively 'shadow' or override the existing task but maybe that's only possible for the builtin Mix tasks.Warehouse
While this is a valid approach, in one-off scenario it is sufficient to call Application.ensure_all_started(:timex) in the body of the migration.Helico

© 2022 - 2024 — McMap. All rights reserved.