Loader Configuration¶
The module loader decides which modules a process loads and how it reacts to load failures. It is driven entirely by settings, so the same image becomes a monolith or a single-module service by configuration alone.
Settings¶
| Setting | Meaning |
|---|---|
SANDLOOM_MODULES |
modules to load explicitly (JSON list of module names or import paths) |
MODULE_LOAD_ENTRYPOINTS |
also load every installed module package (the sandloom.modules entry-point group) |
MODULE_WHITELIST |
allow only listed modules |
MODULE_BLACKLIST |
skip listed modules |
MODULE_REQUIRED |
modules whose load failure aborts startup |
MODULE_FAIL_FAST |
raise on first required failure vs aggregate at the end |
See the Configuration Reference for defaults.
Explicit list¶
SANDLOOM_MODULES='["identity", "tenancy", "billing"]'
create_app() reads SANDLOOM_MODULES, imports each module, and calls its
register(core). Only the listed modules' routes, event schemas, and services
exist in that process. An entry is a module name (identity, the
sandloom.modules entry-point name of an installed module package) or an
import path (sandloom_identity, myapp.modules.tickets); MODULE_REQUIRED,
the whitelist and the blacklist accept the same spellings.
sandloom.main:app, the framework's own composition root, composes every
installed module package (sorted by name) when SANDLOOM_MODULES is unset:
with sandloom[standard] installed that is identity, tenancy and billing. The
kernel names no module.
An application generated by sandloom new needs no list: create_app loads every
module of the app's modules package, so sandloom add module <name> is all it
takes to add one. Set SANDLOOM_MODULES only to select a subset (a single-module
service in the microservices profile, for example).
Module packages¶
A distribution ships a module by registering it in the sandloom.modules
entry-point group. The entry-point name is the module name; the value is the
import path:
# in the module package's pyproject.toml
[project.entry-points."sandloom.modules"]
tickets = "acme_tickets"
Install it and name it in SANDLOOM_MODULES ("tickets"), or load every
installed module package:
MODULE_LOAD_ENTRYPOINTS=true
A requested module name must have one provider. Two installed packages
registering the same name, or an installed package and an app-local module
with the same name (myapp.modules.tickets next to acme_tickets), are
refused before anything loads
(SANDLOOM-B020): uninstall the
package or remove (rename) the local module. See
Module packages.
MODULE_FS_SCAN no longer exists (it scanned sandloom.*, which holds no
module); setting it to true fails startup.
Required modules and fail-fast¶
A module is required unless it says otherwise in its define_module call:
from sandloom.sdk import define_module
register = define_module(__name__, version="1.0.0") # required
# register = define_module(__name__, version="1.0.0", optional=True) # may fail to load
- A required module is only enforced when it is actually present in
SANDLOOM_MODULES, so a billing-only service does not need identity co-deployed. - With
MODULE_FAIL_FAST=truethe loader re-raises on the first required failure; otherwise it aggregates and raisesModuleLoadErrorat the end.
Migration chain keys¶
Each loaded module with a migrations/ directory owns a chain keyed by its
module name (the entry-point name of a module package, else the last dotted
segment of its import path), or by ModuleDescriptor.migrations_chain. Two
loaded modules with the same key (app_a.modules.notes and
app_b.modules.notes) are refused instead of silently sharing
alembic_version_notes — set migrations_chain on one of them. See Migrations Model.
Diagnostics¶
Duplicates and whitelist/blacklist skips are recorded in the load summary, and
the configured modules are reported at /diagnostics/* (requires
INTERNAL_API_TOKEN).