phoenixframework / phoenix

Peace of mind from prototype to production
https://www.phoenixframework.org
MIT License
21.24k stars 2.87k forks source link

Phoenix release using docker - Missing a module in production env #4697

Closed smahi closed 2 years ago

smahi commented 2 years ago

Environment

Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Elixir 1.13.3 (compiled with Erlang/OTP 24)
defp deps do
    [
      {:argon2_elixir, "~> 2.0"},
      {:phoenix, "~> 1.6.4"},
      {:phoenix_ecto, "~> 4.1"},
      {:ecto_sql, "~> 3.4"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_live_view, "~> 0.17.5"},
      {:floki, ">= 0.30.0", only: :test},
      {:phoenix_html, "~> 3.1"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:phoenix_live_dashboard, "~> 0.6"},
      {:telemetry_metrics, "~> 0.6.1"},
      {:telemetry_poller, "~> 1.0"},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.5"},
      {:guardian, "~> 2.2"},
      {:mix_test_watch, "~> 1.1"},
      {:faker, "~> 0.17.0"},
      {:ex_machina, "~> 2.7"},
      {:timex, "~> 3.7"},
      {:esbuild, "~> 0.4", runtime: Mix.env() == :dev},
      {:swoosh, "~> 1.5"},
      {:xlsxir, "~> 1.6"},
      {:oban, "~> 2.10"}
    ]
  end
➜  waqf-dz cat /etc/os-release
NAME="Pop!_OS"
VERSION="20.04 LTS"
ID=pop
ID_LIKE="ubuntu debian"
PRETTY_NAME="Pop!_OS 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://pop.system76.com"
SUPPORT_URL="https://support.system76.com"
BUG_REPORT_URL="https://github.com/pop-os/pop/issues"
PRIVACY_POLICY_URL="https://system76.com/privacy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
LOGO=distributor-logo-pop-os

Expected behavior

Compile Utmaktaba.Prod.Seeds module to be available in production release

Actual behavior

When releasing Phoenix app using mix phx.gen.release --docker in production env, the module would not be compiled for some reason!!! But using normal release (without using docker) the module is compiled and loaded.

Its throw the following errors

nobody@c2bcaf2ac144:/app$ bin/utmaktaba remote
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Interactive Elixir (1.13.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(utmaktaba@c2bcaf2ac144)1> Code.ensure_compiled(Utamktaba.Prod.Seeds)
{:error, :embedded}

iex> Utmaktaba.Prod.Seeds .run()
blahhh .... blahh module not found...

This is my mix file

# mix.exs
def project do
    [
     # ...
      elixirc_paths: elixirc_paths(Mix.env()),
     # ...
    ]
  end

  defp elixirc_paths(:dev), do: ["lib", "dev/support"]
  defp elixirc_paths(:test), do: ["lib", "dev/support", "test/support"]
  defp elixirc_paths(_), do: ["lib", "prod/support"]
josevalim commented 2 years ago

Yes, the seeds file is only in the priv directory, those are not compiled into the app. You can move it to lib if you want to call it inside your production code.

almirsarajcic commented 2 years ago

Sorry, I can't help with the missing module. Maybe someone can figure it out if you put the code of your module.

But I can show you an alternative. This is what I've done for my apps. After I use mix phx.gen.release --docker command, I add the following lines to my lib/<otp_app>/release.ex file:

def seed do
  load_app()

  for repo <- repos() do
    {:ok, _, _} =
      Ecto.Migrator.with_repo(repo, fn repo ->
        # Run the seed script if it exists
        seed_script = priv_path_for(repo, "seeds.exs")

        if File.exists?(seed_script) do
          IO.puts("Running seed script..")
          Code.eval_file(seed_script)
        end
      end)
  end
end

defp priv_path_for(repo, filename) do
  app = Keyword.get(repo.config(), :otp_app)

  repo_underscore =
    repo
    |> Module.split()
    |> List.last()
    |> Macro.underscore()

  priv_dir = "#{:code.priv_dir(app)}"

  Path.join([priv_dir, repo_underscore, filename])
end

and then I'm able to use those inside the rel/overlays/bin/migrate file:

#!/bin/sh
cd -P -- "$(dirname -- "$0")"
exec ./sase_mango eval 'SaseMango.Release.migrate && SaseMango.Release.seed'