Malla is a comprehensive framework that simplifies the development of distributed
services through a plugin-based architecture with compile-time callback chaining,
automatic service discovery across nodes, and minimal "magic" to keep systems
understandable.
See the Introduction guide for a general overview.
API Overview
Service Management
get_service_id/0,get_service_id!/0- Get current service from process dictionary.put_service_id/1- Set service context for current process.get_service_name/1- Get string name (cached for performance).get_service_meta/1- Get metadata (cluster, node, host, service).
Callback Invocation
local/2- Invoke local callback with service_id from process dictionary.local/3- Invoke local callback.remote/3- Invoke remote callback.remote/4- Invoke remote callback with options.call/1- Macro for syntactic sugar to invoke remote callbacks.call/2- Macro for syntactic sugar to invoke remote callbacks with options.
Utilities
metric/4- Record metric with auto-injected metadata.event/2- Generate event with service context.authorize/3- Authorization callback.
See Also
Malla.Service- Service behavior and lifecycle.Malla.Plugin- Plugin development guide.Malla.Tracer- Observability instrumentation.Malla.Node- Service discovery and RPC.
Summary
Functions
Utility function to authorize a request.
Convenient macro to make remote calls more friendly.
Convenient macro to make remote calls more friendly.
Gets the current service ID from the process dictionary, or nil if not defined.
Tries to extract the service ID from the :service_id key in a map or list,
or, if not found, from the process dictionary. See get_service_id/0.
Tries to get the service ID from the process dictionary, or raises Malla.ServiceIdMissing.
See get_service_id/0.
Tries to extract the service ID from the :service_id key in a map or list,
or, if not found, from the process dictionary.
If not found, it raises Malla.ServiceIdMissing. See get_service_id/0.
Returns metadata about a service ID. Cached for fast access.
Returns the string version of a service ID. Cached for fast access.
Invokes a service callback locally at this node.
The service ID must be present in the process dictionary.
See local/3.
Invokes a service callback locally at this node. Service does not need to be running, since this simply
Inserts a new metric value.
Puts a service ID into the process dictionary.
Calls a callback function defined at the home module of a local or remote service,
using Malla.Node.call_cb/4. This could be a normal function defined with def or
a callback function defined with defcb.
Types
@type class() :: atom()
@type config() :: list()
@type id() :: module()
@type metric_opt() :: {:service_id, id()}
@type remote_opt() :: {:timeout, pos_integer()} | {:sna_retries, pos_integer()} | {:excp_retries, pos_integer()} | {:retries_sleep_msec, pos_integer()}
@type service() :: Malla.Service.t()
@type vsn() :: String.t()
Functions
@spec authorize(term(), term(), [authorize_opt()]) :: boolean() | {boolean(), term()} | {:error, term()}
Utility function to authorize a request.
It will simply call Malla.Plugins.Base.malla_authorize/3.
You must implement this callback in your service.
By default it will return {:error, :auth_not_implemented}.
Convenient macro to make remote calls more friendly.
It calls remote/4 with the module, function name, and arguments extracted from the given expression.
Examples
call Module.fun(:a, :b), timeout: 5000
# Translates to: remote(Module, :fun, [:a, :b], timeout: 5000)
Convenient macro to make remote calls more friendly.
It calls remote/3 with the module, function name, and arguments extracted from the given expression.
Examples
call Module.fun(:a, :b)
# Translates to: remote(Module, :fun, [:a, :b])
@spec get_service_id() :: id() | nil
Gets the current service ID from the process dictionary, or nil if not defined.
On each callback call, called using local/3 or remote/4, the service ID is always inserted in the process dictionary.
Tries to extract the service ID from the :service_id key in a map or list,
or, if not found, from the process dictionary. See get_service_id/0.
@spec get_service_id!() :: id()
Tries to get the service ID from the process dictionary, or raises Malla.ServiceIdMissing.
See get_service_id/0.
Tries to extract the service ID from the :service_id key in a map or list,
or, if not found, from the process dictionary.
If not found, it raises Malla.ServiceIdMissing. See get_service_id/0.
@spec get_service_meta(id()) :: %{ cluster: String.t(), node: String.t(), host: String.t(), service: String.t() }
Returns metadata about a service ID. Cached for fast access.
clusteris extracted from:mallaapplication's:malla_clusterenvironment variable.nodeis the current Erlang node.hostis the first part of the node name.serviceusesget_service_name/1.
Returns the string version of a service ID. Cached for fast access.
Invokes a service callback locally at this node.
The service ID must be present in the process dictionary.
See local/3.
Invokes a service callback locally at this node. Service does not need to be running, since this simply:
- puts service ID into process dictionary.
- calls
Malla.Plugins.Base.service_cb_in/3, which, if not overridden, will ultimately call the indicated function. - sets back previous value in process dictionary, if any.
@spec metric(atom() | [atom()], number() | map() | keyword(), map() | keyword(), [ metric_opt() ]) :: :ok
Inserts a new metric value.
It calls :telemetry.execute/3 with the given class, value and meta.
class: Taken from the calling arg, but converted to a list if it is not already.value: If it is a number, it is converted to%{value: <number>}. If it is a list, it is converted to a map.meta: Merged with the service's metadata obtained fromget_service_meta/1. The service ID must be inoptsor the process dictionary.
Puts a service ID into the process dictionary.
This is used to mark the current process as belonging to this service. Callbacks called for a module will have it already.
If id is nil or :undefined, the key is deleted.
@spec remote(id(), atom(), [any()], [remote_opt()]) :: any()
Calls a callback function defined at the home module of a local or remote service,
using Malla.Node.call_cb/4. This could be a normal function defined with def or
a callback function defined with defcb.
On the remote side, the process leader will be changed to :user so that IO responses are not
sent back to the caller. It will set the correct service ID in the process dictionary and call
the callback function Malla.Plugins.Base.service_cb_in/3, which, if not overridden, will
ultimately call the indicated function.
If the {:error,
malla_service_not_available} is returned, it meansMalla.Nodecould not find any service to process the request. The call will be retried ifsna_retriesis defined (default value is 5). The sleep time between retries can be set withretries_sleep_msec, and it is 1000 by default.This is very convenient in situations when the remote service is not yet available, because it may be starting or our node could not yet discover the service.
If an exception is produced during the call, the call is retried only if
excp_retriesis defined. Otherwise, the error{:error, {:malla_rpc_error, <error_data>}}is returned. Defaultexcp_retriesis 0.Be very careful when activating these retries, since the request could have been processed partially on the remote side, and you may re-execute it.
The default timeout is 15000 ms.
You can instrument the call by overriding
Malla.Plugins.Base.service_cb_in/3.