A service in Malla is a module that uses Malla.Service and implements one or more callbacks. Services are the core building block of a Malla application and can run locally or be distributed across a cluster.
By using use Malla.Service, a module gains:
- Automatic Discovery: Becomes visible to all nodes in the cluster (if
global: true). - Plugin Architecture: Extensibility through a compile-time callback chain.
- Status Management: Administrative control (
:active,:pause,:inactive). - Supervision: A standard supervisor for service-specific children.
- ETS Storage: A runtime data store that is created on start and destroyed on stop.
- Observability: Built-in tracing and introspection hooks.
Defining a Service
To define a service, you use Malla.Service in your module and implement your business logic.
defmodule MyService do
use Malla.Service,
global: true,
plugins: [SomePlugin],
vsn: "1.0.0"
# A regular function - available for remote calls but not in the callback chain.
def my_function(arg), do: arg
# A callback - participates in the plugin chain.
defcb my_callback(arg) do
# do work...
:cont # or return a value to stop the chain
end
endFunctions vs. Callbacks
Services expose two types of operations:
- Regular Functions (defined with
def): Standard Elixir functions that can be called remotely but do not participate in the plugin callback chain. - Callbacks (defined with
defcb): Functions that are part of the plugin chain, allowing plugins to intercept, modify, or extend their behavior.
See the Callbacks guide for a detailed explanation.
Service Options
You can configure a service via options in the use Malla.Service macro:
:global- (boolean) Iftrue, the service is registered cluster-wide and can be called from any node. Defaults tofalse.:plugins- (list of modules) A list of plugins to include in the service's callback chain. See Plugins.:vsn- (string) The service version, used for compatibility checking.:otp_app- (atom) Load additional configuration from the specified OTP application's environment.- Any other key-value pairs are added to the service's initial configuration. See the Configuration guide.
Service Lifecycle
Services have two independent status dimensions:
- Admin Status:
:active,:pause,:inactive. This is controlled by the administrator/operator. - Running Status:
:starting,:running,:paused,:stopped,:failed. This is the operational state managed by the system.
For a detailed explanation of the service lifecycle, see the Lifecycle guide.
Starting a Service
You can start a service directly or as part of a supervisor tree.
# Start the service directly
{:ok, pid} = MyService.start_link()
# Start with runtime configuration
{:ok, pid} = MyService.start_link(key: :value)
# Start under a supervisor
children = [
{MyService, key: :value}
]
Supervisor.start_link(children, strategy: :one_for_one)Service Storage
Each service instance is provided with its own ETS table for storing runtime data. This table is created when the service starts and destroyed when it stops.
See Storage and State guide for details.
Next Steps
- Plugins - Understand the plugin system.
- Callbacks - Learn more about callback chains.
- Lifecycle - Get a deep dive into the service lifecycle.
- Configuration - Learn how to configure your services.
- Reconfiguration - Learn how to update service configuration at runtime.