在Elixir部署时更改后端/模块? [英] Change backend/module at deploy time in Elixir?

查看:50
本文介绍了在Elixir部署时更改后端/模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何实现可替换的后端(或基本上任何部分或模块),以便可以在Elixir的配置/部署时对其进行替换?

How would one go about implementing a replaceable backend (or basically any part or module) so that it can be replaced at configuration/deploy time in Elixir?

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

My specific situation is a simple web app (in this case using Phoenix but I'm guessing this question applies to other situations as well) where I have a very simple backend using Agent to keep state but I see a need in the future for being able to switch out the backend more or less dynamically.

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

I'm guessing both Ecto and Logger do this to some degree but being new to Elixir it's hard to know where to look.

推荐答案

这可以通过主管的参数来处理.例如,Ecto的后端主管使用名为adapter的参数来指定应使用哪种数据库:

This can be handled through an argument to the supervisor. For example, Ecto's backend supervisor takes an argument called adapter to specify which kind of database should be used:

# 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

您可以在应用程序中执行相同的操作,只需start_link的一个参数就足够了–我们将其称为backend

You could do the same in your application, probably a single argument to start_link will be enough – let's call it 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

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

Now, you can of course set that argument dynamically when you spin up your application, based on a configuration file:

# 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

现在,唯一缺少的部分是如何从配置文件获取后端.没有唯一的答案,因为这样做的方式有多种.

Now, the only piece that is missing is how to get the backend from a configuration file. There's no single answer to that because there are multiple ways of doing this.

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

You can simply use the existing Mix configuration, but it has the downside that you need to recompile the application every time the configuration changes:

# my_app/config/config.exs

use Mix.Config
config :my_app, backend: MyApp.SpecificBackend

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

Then adjust your application to read in the specified backend:

# 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

滚动自己的

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

Roll your own

You could also implement your own config file. I am not going into detail here, but this is the rough idea:

  • 将配置文件保存在某处
  • 在Elixir中阅读解析
  • 使用String.to_existing_atom("Elixir.#{module_name}")
  • 将字符串转换为模块名称
  • 如果原子(因此模块名称)不存在,这将引发错误
  • 在您的def backend函数中使用它
  • Keep a config file somewhere
  • Read an parse it in Elixir
  • Convert the string to a module name with String.to_existing_atom("Elixir.#{module_name}")
  • This will raise an error if the atom (thus the module name) does not exist
  • use it in your def backend function

基本上是先前解决方案的一个美化版本.仔细搜索了一下,我发现了一个名为符合的库.看起来很有趣,但是我不能做任何承诺,因为我从来没有亲自使用过它.

Basically a glorified version of the previous solution. Googling around a bit I found a library called Conform. It looks interesting but I can'T make any promises because I've never used it myself.

这篇关于在Elixir部署时更改后端/模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆