Change backend / module during deployment in Elixir?

How can I implement a replaceable backend (or basically any part or module) so that it can be replaced during setup / deployment time in Elixir?

My specific situation is a simple web application (in this case using Phoenix, but I guess this question applies to other situations too), where I have a very simple backend using Agent to save state, but I see the need for the future for the possibility of a faster or minimal inclusion of the backend.

I assume that both Ecto and Logger do this to some extent, but being new to Elixir, it's hard to figure out where to look.

+5
source share
1 answer

This can be handled with an argument to the supervisor. For example, the Ecto supervisor uses the adapter argument to indicate which type of database to use:

 # 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 

You can do the same in your application, maybe one argument for start_link will be enough - 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 this argument dynamically when deploying the application based on the 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 part that is missing is how to get the backend from the configuration file. There is no single answer to this, because there are several ways to do this.

Mix Configuration

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

 # my_app/config/config.exs use Mix.Config config :my_app, backend: MyApp.SpecificBackend 

Then configure the 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 

Create your own

You can also implement your own configuration file. I will not go into details here, but this is a rough idea:

  • Store the configuration file somewhere
  • Read the parsing in Elixir
  • Convert string to module name using String.to_existing_atom("Elixir.#{module_name}")
  • This will throw an error if the atom (thus the module name) does not exist
  • use it in your def backend function

Use Existing Runtime Configuration Library

Basically an illustrious version of the previous solution. Several times I searched for a library called Conform . It looks interesting, but I can not do promises because I never used it myself.

+7
source

Source: https://habr.com/ru/post/1208289/


All Articles