With the release of Elixir 1.9, we have the option to not use Distillery for creating app releases anymore.
While I understand that we can still use the ReleaseTasks from Distillery, I still can’t get it to work because it doesn’t see the database at runtime.
# config/config.exs
import Config
config :my_app,
ecto_repos: [MyApp.Repo]
# Configures the endpoint
config :my_app, MyAppWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "SyIMuifvLpc1Wtd0XQWhY9ajIKfwRdExf5L0yKrXM33o9yLEPAJ94L4UjqMRehLc",
render_errors: [view: MyAppWeb.ErrorView, accepts: ~w(json)],
pubsub: [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2]
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
import_config "#{Mix.env()}.exs"
# config/prod.exs
import Config
config :my_app, MyAppWeb.Endpoint,
check_origin: false
config :logger, level: :info
# config/releases.exs
import Config
config :my_app, MyAppWeb.Endpoint,
http: [port: String.to_integer(System.fetch_env!("PORT"))],
url: [host: System.fetch_env!("HOST"), port: String.to_integer(System.fetch_env!("PORT"))],
server: true,
secret_key_base: System.fetch_env!("SECRET_KEY_BASE")
config :my_app, MyApp.Repo,
hostname: System.fetch_env!("DB_HOSTNAME"),
username: System.fetch_env!("DB_USERNAME"),
password: System.fetch_env!("DB_PASSWORD"),
database: System.fetch_env!("DB_NAME"),
pool_size: String.to_integer(System.fetch_env!("DB_POOL_SIZE"))
# lib/release_tasks.ex
defmodule MyApp.ReleaseTasks do
@start_apps [
:crypto,
:ssl,
:postgrex,
:ecto,
:ecto_sql # If using Ecto 3.0 or higher
]
@repos Application.get_env(:my_app, :ecto_repos, [])
def migrate() do
start_services()
run_migrations()
stop_services()
end
def seed() do
start_services()
run_migrations()
run_seeds()
stop_services()
end
defp start_services do
IO.puts("Starting dependencies..")
# Start apps necessary for executing migrations
Enum.each(@start_apps, &Application.ensure_all_started/1)
# Start the Repo(s) for app
IO.puts("Starting repos..")
# pool_size can be 1 for ecto < 3.0
Enum.each(@repos, & &1.start_link(pool_size: 2))
end
defp stop_services do
IO.puts("Success!")
:init.stop()
end
defp run_migrations do
Enum.each(@repos, &run_migrations_for/1)
end
defp run_migrations_for(repo) do
app = Keyword.get(repo.config(), :otp_app)
IO.puts("Running migrations for #{app}")
migrations_path = priv_path_for(repo, "migrations")
Ecto.Migrator.run(repo, migrations_path, :up, all: true)
end
defp run_seeds do
Enum.each(@repos, &run_seeds_for/1)
end
defp run_seeds_for(repo) do
# 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
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
end
$ MIX_ENV=prod mix release
$ PORT="4000" HOST="127.0.0.1" SECRET_KEY_BASE="JdgV1bdEtGnR2hM4DFXt9+gJnLfSSOssp1Z8YEpnNbXiBhvYYZ14WwYRMlDGGhLQ" DB_HOSTNAME=localhost DB_USERNAME=postgres DB_PASSWORD=postgres DB_NAME=my_app_dev DB_POOL_SIZE="15" _build/prod/rel/my_app/bin/my_app eval "MyApp.ReleaseTasks.migrate"
Starting dependencies..
Starting repos..
Running migrations for my_app
14:31:03.619 [error] GenServer #PID<0.217.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
(elixir) lib/keyword.ex:393: Keyword.fetch!/2
(postgrex) lib/postgrex/protocol.ex:90: Postgrex.Protocol.connect/1
(db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
14:31:03.619 [error] GenServer #PID<0.218.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
(elixir) lib/keyword.ex:393: Keyword.fetch!/2
(postgrex) lib/postgrex/protocol.ex:90: Postgrex.Protocol.connect/1
(db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
14:31:03.622 [error] GenServer #PID<0.220.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
(elixir) lib/keyword.ex:393: Keyword.fetch!/2
(postgrex) lib/postgrex/protocol.ex:90: Postgrex.Protocol.connect/1
(db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
14:31:03.622 [error] GenServer #PID<0.219.0> terminating
** (RuntimeError) connect raised KeyError exception: key :database not found. The exception details are hidden, as they may contain sensitive data such as database credentials. You may set :show_sensitive_data_on_connection_error to true when starting your connection if you wish to see all of the details
(elixir) lib/keyword.ex:393: Keyword.fetch!/2
(postgrex) lib/postgrex/protocol.ex:90: Postgrex.Protocol.connect/1
(db_connection) lib/db_connection/connection.ex:69: DBConnection.Connection.connect/2
(connection) lib/connection.ex:622: Connection.enter_connect/5
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: nil
** (EXIT from #PID<0.164.0>) shutdown
In Distillery, I would use "${DB_NAME}"
instead of System.fetch_env!("DB_NAME")
and setting REPLACE_OS_VARS=true
and the above code/commands will work. It doesn’t work for Elixir 1.9’s release command though.
Do I need to define the database config somewhere else?