创建发布版本后无法 运行 在 elixir 中发布应用程序

Unable to run release application in elixir after creating release build

我已经使用命令 MIX_ENV=prod mix release --env=prod --verbose 创建了构建。它成功创建了构建,我可以 运行 consoleping 命令并给我 pid。即使我 运行 启动命令成功启动,但当我转到 htttp://localhost:4000 时,服务器没有 运行。当我 运行 _build/prod/rel/project/bin/project foreground 命令时,它只是挂在那里没有输出。

我使用的是 MacOS 版本:10.13.2,elixir:1.6.5(使用 OTP 19 编译),otp:Erlang/OTP 20。这是日志

$ MIX_ENV=prod mix release --env=prod --verbose
Generated project app
==> Loading configuration..
==> Assembling release..
==> Building release project:0.0.1 using environment prod
==> One or more direct or transitive dependencies are missing from
    :applications or :included_applications, they will not be included
    in the release:

    :jsx

    This can cause your application to fail at runtime. If you are sure that this is not an issue, you may ignore this warning.
==> Release successfully built!
You can run it in one of the following ways:
  Interactive: _build/prod/rel/project/bin/project console
  Foreground: _build/prod/rel/project/bin/project foreground
  Daemon: _build/prod/rel/project/bin/project start

我已经包含了所有显示为警告的应用程序,除了 jsx 因为它显示了未定义应用程序的错误。

我还更详细地讨论了酒厂问题 https://github.com/bitwalker/distillery/issues/276 and as this issue suggest I checked my app name and server is true set in the config file so it did not help. I have also logged issue here https://github.com/bitwalker/distillery/issues/433

这是我的发布文件配置

environment :prod do
  set include_erts: true
  set include_src: false
  set cookie: :"lfHBC,7lDxe6kbZJ%M.x4=r!>[F*DhL)ly`?d$>%iE=9y)V4_Oulis?4Rvm)~!55"
end

# You may define one or more releases in this file.
# If you have not set a default release, or selected one
# when running `mix release`, the first release in the file
# will be used by default

release :project do
  set version: current_version(:project)
  set applications: [
    :runtime_tools
  ]
end

当我尝试创建一个新的 phoenix 应用程序并正确执行相同操作时 运行s 并监听端口 4000 并输出前台命令但在我的应用程序中使用相同的配置,它不监听 4000 端口并挂在前台命令上。当我看到两者的 netstat 时,我的应用程序似乎没有 运行ning 4000 端口,请参阅

我不确定我还应该如何调试这个问题我已经尝试了所有可能的方法。如果有人需要更多信息,请告诉我。在这方面,我将不胜感激 help/suggestion。

编辑: 这是我的配置和产品 files.I 刚刚粘贴了端点详细信息让我知道是否还有其他需要。

# config.exs
config :project, Project.Endpoint,
  url: [host: "localhost"],
  secret_key_base: some_secret_key,
  render_errors: [view: Project.ErrorView, accepts: ~w(html json)],
  check_origin: false,
  pubsub: [name: Project.PubSub, adapter: Phoenix.PubSub.PG2]

# prod.exs
config :project, Project.Endpoint,
  http: [port: 4000],
  url: [scheme: "https", host: "server.example.com", port: 443],
  server: true,
  code_reloader: false

好吧,基于评论中的调试步骤,我认为我们的答案在于使用开发 phoenix 服务器时的配置与发布本身之间的差异。

配置工作方式不同的关键原因是开发服务器最常用于 运行 您机器上的本地 - 因此它很自然地 运行 关闭开发服务器上存在的环境变量机器,并在本地 运行 时间提供配置。

但是,版本旨在 运行 在远程机器上 ,通常在物理上或虚拟上与构建版本的机器不同的机器上。

这意味着严重依赖 运行时间配置的功能必须在版本中以不同方式处理。 (Several crucial values of Phoenix.Endpoint like :port, :host, etc fall under this)

随着版本的使用在 Elixir 中的发展,有几种不同的最佳实践或模式可用于弥合配置中的这种差异,这在很大程度上要归功于 Distillery。我认为今天的社区是一个非常健康的地方。

编译版本时,它无法访问最终 运行 机器的 运行 时间。因此,如果模块需要 运行time 配置,将配置委托给启动模块的 Supervisor 是一个很好的方法。在 Supervisor 初始化模块时,它已在远程机器上启动,现在可以访问该远程环境。

有两个模块我几乎总是在 supervisor 启动时配置:Ecto 的 Repo 和 Phoenix 的 Endpoint

实际上,您可以通过将 load_from_system_env 值设置为 true,告诉 Endpoint 从远程计算机的 运行 时间配置自身。您需要确保通过 export PORT=4000export HOST=localhost 或采购 .env 文件在环境中设置 PORT HOST 的值,这将当 运行 发布版本和最终 运行 发布的远程机器时,本地机器上的行为相同(假设两台机器具有相同的环境值):

# config/prod.exs
config :trackbees, TrackbeesWeb.Endpoint,
  load_from_system_env: true,
  ...

Phoenix.Endpoint is to act as a wrapper 的角色之一,用于作为监督树的一部分启动和停止端点。作为包装策略的一部分,它提供了一个 init/2 回调。你会看到当 init/2 触发时,它将在 :load_from_system_env:

上进行模式匹配
# trackbees/lib/trackbees_web/endpoint.ex
def init(_key, config) do
  if config[:load_from_system_env] do
    Keyword.put ...

我认为这是解决 Trackbees 目前遇到的问题的具体方法。我建议添加 load_from_system_env 配置值,并可能在 if 语句 上方插入一条调试语句,如 IO.inspect 以验证该值是否正在获取通过.

仅供参考,如果您也使用 Ecto,则有一个匹配的 init 包装器,如果您也愿意,可以以类似的方式使用它:

# lib/trackbees/repo.ex
def init(_, opts) do
  case Application.get_env(:trackbees, :env) do
    :test ->
      {:ok, opts}

    _ ->
      opts =
        opts
        |> Keyword.put(:url, System.get_env("DATABASE_URL"))
        |> Keyword.put(:username, System.get_env("DB_USERNAME"))
        |> Keyword.put(:password, System.get_env("DB_PASSWORD"))
        |> Keyword.put(:database, System.get_env("DB_NAME"))
        |> Keyword.put(:hostname, System.get_env("DB_HOSTNAME"))

      {:ok, opts}
  end
end