I want to create something like a plugin system: a bunch of modules which get loaded/unloaded dynamically, add I insert/remove them.
Something like this:
# plugin1.eex
defmodule MyApp.Plugins.Plugin1 do
def plugin_main_func(arg1, arg2) do
# some stuff
end
end
# plugin2.eex
defmodule MyApp.Plugins.Plugin2 do
def plugin_main_func(arg1, arg2) do
# some stuff 2
end
end
# plugin3.eex
defmodule MyApp.Plugins.Plugin3 do
def plugin_main_func(arg1, arg2) do
# some stuff 3
end
end
They'll have the same common function - "plugin_main_func" - which implementation will be different for each plugin. And somewhere in my app I'll have this:
plugins = load_plugins()
Enum.each plugins, &(&1.plugin_main_func(1, "fdafdsfds"))
I then be able to add or remove plugins by creating or removing appropriate modules or files. Without having to hard-code/add/remove their names somewhere in an application as a list of strings as well.
How can I achive this?
Update:
Given that a plugin must live in MyApp.Plugins and have a function plugin_main_func
, how can I observe a list of plugins they are currently present? I mere want to avoid hard-coding their names somewhere and load or run them only having these 2 conditions which are sufficient for finding all the plugins.
When I find all of them, dynamically or semi-dynamically, I want to somehow be able to call plugin_main_func
in each plugin. Without knowing the number of plugins and their exact names. How?
I'm fine with loading them before compilation, not exactly at runtime.
Answering the question, stated in the title: yes, it is possible to dynamically load/unload modules in Elixir. Compile code with e.g. Code.ensure_compiled/1
and purge it with Erlang’s code
module:
:code.delete MyApp.Plugins.Plugin1
:code.purge MyApp.Plugins.Plugin1
Answering the whole question: you are doing it wrong. Elixir is a compiled language and you are abusing it. Compilation in a runtime is definitely not what Elixir is good for.
All you need is to keep a list of “loaded” plugins to fake the behavior you are trying to achieve. load
would add a module name to a list and unload
would remove it from there. And that is it. You do not need to load/unload anything in a runtime: it’s extremely ineffective, dangerous and counter-idiomatic. If you need good runtime plugin support—go for lua, ruby, python or even javascript.
To get the list of loaded modules in a runtime, one might use:
:application.get_key(:my_app, :modules)
You might restrict plugins to the desired namespace (e.g. MyApp.Plugins
) and filter the list by that name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With