Malla.Plugin behaviour (malla v0.0.1-rc.1)

Copy Markdown View Source

Defines the core behavior for a Malla plugins.

By use Malla.Plugin, a module is transformed into a plugin that can be inserted into a Malla.Service. Malla.Plugin enables the creation of reusable, composable modules that provide or modify service behavior through compile-time callback chaining.

This module also provides a set of callbacks that will have a default implementation if not overriden in your plugin module.

For comprehensive documentation, please see the guides:

  • Plugins: For an overview of creating and using plugins.
  • Callbacks: For understanding the callback chain.
  • Lifecycle: For hooking into the service lifecycle.

Summary

Types

Options for configuring a service when using Malla.Plugin.

Callbacks

Optional callback called before service's start. It allows the plugin to check and, if needed, modify the config.

Optional callback called when merging configuration updates.

Optional callback called during service's start.

Optional callback called if service needs to 'stop' this plugin.

Optional callback called after service's reconfiguration. (See Malla.Service.reconfigure/2). You are presented with old and new config, and you have the chance to restart the plugin.

Functions

Macro that transforms a module into a Malla plugin.

Macro for defining plugin callbacks.

Types

child_spec()

@type child_spec() ::
  Supervisor.child_spec()
  | {module(), term()}
  | module()
  | (old_erlang_child_spec :: :supervisor.child_spec())

id()

@type id() :: Malla.id()

start_opt()

@type start_opt() ::
  {:children, child_spec()} | Supervisor.option() | Supervisor.init_option()

updated_opts()

@type updated_opts() :: {:restart, boolean()}

use_opt()

@type use_opt() ::
  {:plugin_deps, [module() | {module(), [{:optional, boolean()}]}]}
  | {:group, atom()}

Options for configuring a service when using Malla.Plugin.

Options include:

  • :plugin_deps - Declares this plugin depends on these other plugins. Optional plugins are included only if they can be found in the source code.

    For example: use Malla.Plugin, plugin_deps: [Plugin1, {Plugin2, optional: true}]

    This plugin will be marked as dependant on Plugin1 and Plugin2, meaning that they will be inserted first in the plugin chain list, so:

    • they will be started first, before this plugin.
    • callbacks implemented by all will reach first our plugin, then Plugin1 and Plugin2.
    • since Plugin2 is marked as optional, if it is not found, it is not included in the list.
  • :group - Declares plugin group. All plugins belonging to the same 'group' are added a dependency on the previous plugin in the same group

    For example: , so for example, if we define in our service use MallaService, plugins: [PluginA, PluginB, PluginC]

    If they all declare the same group, PluginB will depend on Plugin A and PluginC will depend on PluginB, so they will be started in the exact order PluginA -> PluginB -> PluginC. Callbacks will call first PluginC, then B and A.

Callbacks

plugin_config(id, config)

(optional)
@callback plugin_config(Malla.id(), config :: keyword()) ::
  :ok | {:ok, config :: keyword()} | {:error, term()}

Optional callback called before service's start. It allows the plugin to check and, if needed, modify the config.

See Configuration.

Top level plugins are called first, so they could update the config for other plugins they declared as dependants.

plugin_config_merge(id, old_config, update)

(optional)
@callback plugin_config_merge(Malla.id(), old_config :: keyword(), update :: keyword()) ::
  :ok | {:ok, merged_config :: keyword()} | {:error, term()}

Optional callback called when merging configuration updates.

This callback is invoked during service initialization (when runtime config is merged with static config) and when Malla.Service.reconfigure/2 is used.

By default, if a plugin doesn't implement this callback, configurations are deep-merged automatically. Implement this callback when you need custom merge logic for your plugin's configuration keys.

Top-level plugins (service itself, then declared plugins) are called first, allowing higher-level plugins to process configuration before lower-level ones.

plugin_start(id, config)

(optional)
@callback plugin_start(Malla.id(), config :: keyword()) ::
  :ok | {:ok, [start_opt()]} | {:error, term()}

Optional callback called during service's start.

Plugins will be started on service init, starting with lower-level plugins up to the service itself (that is also a Plugin). See Lifecycle for details.

Plugin can return a child specification, in this case a Supervisor will be started with the specified children.

The service will monitor this supervisor, and, if it fails, the whole service will be marked as 'failed' and we will retry to start it, calling this function again.

plugin_stop(id, config)

(optional)
@callback plugin_stop(Malla.id(), config :: keyword()) :: :ok | {:error, term()}

Optional callback called if service needs to 'stop' this plugin.

This can happen if we mark the service as inactive. Top-level plugins will be stopped first starting with the service itself (that is also a Plugin), up to lower level plugins in order.

It can also happen if this plugin is removed from the service.

After calling this function, service will stop the started children supervisor, if it was defined and it is already running.

plugin_updated(id, old_config, new_config)

(optional)
@callback plugin_updated(
  Malla.id(),
  old_config :: keyword(),
  new_config :: keyword()
) :: :ok | {:ok, [updated_opts()]} | {:error, term()}

Optional callback called after service's reconfiguration. (See Malla.Service.reconfigure/2). You are presented with old and new config, and you have the chance to restart the plugin.

Lower level plugins are called first.

Functions

__using__(opts)

(macro)
@spec __using__([use_opt()]) :: Macro.t()

Macro that transforms a module into a Malla plugin.

This macro inserts required functions, implements plugin callbacks and registers Malla callbacks

See use_opt/0 for configuration options.

defcb(ast, list)

(macro)

Macro for defining plugin callbacks.

Callbacks will appear at service's module and will participate in the callback chain.

A Malla callback can return any of the following:

  • :cont: continues the call to the next function in the call chain
  • {:cont, [:a, b:]}: continues the call, but changing the parameters used for the next call in chain. The list of the array must fit the number of arguments.
  • {:cont, :a, :b}: equivalent to {:cont, [:a, :b]}
  • any: any other response stops the call chain and returns this value to the caller