在Elixir的部署时更改后端/模块?

sto*_*oft 5 elixir phoenix-framework

如何实现可更换的后端(或基本上任何部件或模块),以便在Elixir的配置/部署时更换它?

我的具体情况是一个简单的网络应用程序(在这种情况下使用凤凰,但我猜这个问题也适用于其他情况)我有一个非常简单的后端Agent用于保持状态但我认为将来需要能够或多或少地动态切换后端.

我猜测Ecto和Logger都在某种程度上做到这一点,但对Elixir来说是新手,很难知道在哪里看.

Pat*_*ity 7

这可以通过主管的参数来处理.例如,Ecto的后端主管接受一个调用的参数adapter来指定应该使用哪种数据库:

# https://github.com/elixir-lang/ecto/blob/364d34bb135e2256fd48327464ada7f7fa2976f9/lib/ecto/repo/backend.ex#L13-L16

def start_link(repo, adapter) do
  # Start Ecto, depending on the supplied <repo> and <adapter>
end
Run Code Online (Sandbox Code Playgroud)

您可以在您的应用程序中执行相同的操作,可能只需一个参数即可start_link- 让我们称之为backend

# my_app/lib/my_app/supervisor.ex

defmodule MyApp.Supervisor do
  def start_link(backend) do
    # use <backend> as you need to in here,
    # it will contain the module that is
    # specified in the configuration file.
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以根据配置文件在启动应用程序时动态设置该参数:

# my_app/lib/my_app.ex

defmodule MyApp do
  use Application

  def start(_type, _args) do
    MyApp.Supervisor.start_link(backend)
  end

  # get backend from configuration
  def backend do
    # ???
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,唯一缺少的是如何从配置文件中获取后端.对此没有单一的答案,因为有多种方法可以做到这一点.

混合配置

您可以简单地使用现有的Mix配置,但是每次配置更改时,您都需要重新编译应用程序:

# my_app/config/config.exs

use Mix.Config
config :my_app, backend: MyApp.SpecificBackend
Run Code Online (Sandbox Code Playgroud)

然后调整您的应用程序以读取指定的后端:

# my_app/lib/my_app.ex

defmodule MyApp do
  use Application

  def start(_type, _args) do
    # same as above ...
  end

  def backend do
    Application.get_env(:my_app, :backend)
  end
end
Run Code Online (Sandbox Code Playgroud)

滚动你自己

您还可以实现自己的配置文件.我不会在这里详细介绍,但这是一个粗略的想法:

  • 将配置文件保存在某处
  • 阅读Elixir中的解析
  • 用字符串将字符串转换为模块名称 String.to_existing_atom("Elixir.#{module_name}")
  • 如果原子(因此模块名称)不存在,这将引发错误
  • 在你的def backend功能中使用它

使用现有的运行时配置库

基本上是以前解决方案的美化版本.谷歌搜索了一下我发现了一个名为Conform的库.它看起来很有趣,但我不能做出任何承诺,因为我自己从未使用它.