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

时间:2018-07-18 09:09:00

标签: elixir phoenix-framework release distillery

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

我正在使用MacOS版本:10.13.2 ,,剂:1.6.5(与OTP 19编译),otp:Erlang / OTP20。这是日志

$ 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,并且由于这个问题的建议,我检查了我的应用程序名称,并且服务器在配置文件中的设置正确,因此没有帮助。我还在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应用程序并执行相同的操作时,它可以正常运行并监听端口4000和输出前景色命令,但在我的应用程序中具有相同的配置时,它不监听4000端口并挂在前景命令上。当我看到两者的netstat时,似乎我的应用程序未运行4000端口,请参见 enter image description here

我不确定我应该如何尝试解决所有可能的问题。请让我知道是否有人需要更多信息。在这方面的任何帮助/建议,我将不胜感激。

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

# 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

1 个答案:

答案 0 :(得分:1)

好的,基于注释中的调试步骤,我认为我们的答案在于使用开发凤凰服务器时的配置与发行版本身之间的区别。

配置工作不同的关键原因是开发服务器通常旨在在您的计算机上本地运行-因此,很自然地,它可以利用开发计算机上存在的环境变量运行配置,并在本地使用可用配置运行时。

但是,发行版旨在在远程计算机上运行,通常在物理上或实际上与发行版所基于的计算机不同的计算机上运行。

这意味着在很大程度上依赖于运行时配置的功能在发行版中必须以不同的方式进行处理。 (Several crucial values of Phoenix.Endpoint like :port, :host, etc fall under this)

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

编译发行版时,它无权访问最终将在其上运行的计算机的运行时。因此,如果模块需要运行时配置,则将其配置委派给引导该模块的Supervisor是一种很好的方法。在Supervisor初始化模块时,它已在远程计算机上启动,现在可以访问该远程环境。

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

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

# 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配置值,并可能在IO.inspect语句上方插入if 上方这样的调试语句以验证该值是否通过。 / p>

仅供参考,如果您也使用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