Reload¶
rel doesn't embed a migration tool. reload.cmd names whatever command you want run before
every reload — a migration tool, a plain SQL script via psql, or nothing at all if you manage
the schema some other way.
When it runs¶
reload.cmd runs at every startup, before rel first introspects the schema, and again on every
SIGUSR1:
New requests get 503 for as long as a SIGUSR1 reload is in flight; in-flight requests get up
to reload.drain_timeout (default 30s) to finish before rel cancels their context outright, so
a straggler can't hold a Postgres lock indefinitely against reload.cmd's own DDL.
reload.cmd empty (the default) skips this step entirely — rel still reintrospects and rebuilds
its registries, it just runs nothing beforehand.
Command line and interpolation¶
reload.cmd is a single string, split into arguments with shell-style word-splitting/quoting
rules (so quote an argument that contains spaces). Before splitting,
{name}/{name1:name2:...:default} placeholders are substituted :
{name}, whennamecontains a., resolves it as a configuration key — e.g.{pg.uri}. Otherwise it resolves as an environment variable — e.g.{HOME}.{name}with no default and an unresolvednameis an error —reload.cmdnever runs.{name1:name2:...:default}tries eachnamein order (same dotted-config-key/env-var rule as above) and substitutes the first one that resolves to a non-empty value. An unset name, or one that resolves to an empty string, is skipped in favor of the next candidate.- The last segment is always a literal fallback, never resolved as a name — e.g. in
{DMUT_USER:pg.user:user},useris used as-is if neitherDMUT_USERnorpg.userresolve to a non-empty value.
A substituted value is inserted as raw text, not as a pre-quoted token — wrap it in quotes
within reload.cmd if it may contain spaces:
[reload]
cmd = 'dmut apply "{pg.uri}" /migrations'
timeout = 120 # seconds ; reload.cmd is aborted and considered failed past this
A literal {/} anywhere in reload.cmd is always parsed as a placeholder attempt — there is
no escape syntax. A command that needs a literal brace should produce it at runtime (an
environment variable, a here-string) rather than write it directly into reload.cmd.
The spawned process receives the full parent environment, unmodified, in addition to whatever
was substituted into the command line — this is what makes Docker/Kubernetes/Swarm secret
injection work for reload.cmd : put the secret in an env var the orchestrator already injects,
and reference it as {THAT_VAR} (or let the process read it directly, since the full
environment is passed through either way). It is your own responsibility not to expose secrets
through the config-key side of interpolation — every resolved configuration value is available
to it.
Output and failure handling¶
reload.cmd's stdout and stderr are logged line by line, tagged stream=stdout/stream=stderr
(alongside the usual module attribute). A line that parses as a JSON object has its own keys
merged into the log record on top of that, for tools that support structured output.
If reload.cmd exits non-zero or exceeds reload.timeout, rel skips reintrospecting the schema
for that reload — but still rebuilds the well-known query registry and Jet
template cache, against the
previous, still-loaded schema, so a well-known-query or template change on disk still takes
effect even when the migration step itself failed. A reintrospection, /route registry, or mux
build failure past that point leaves the previous schema, registry, and templates running
untouched — the same "log and continue" behavior throughout.
Using dmut¶
dmut — a dependency-graph migration tool, not a sequential up/down list : each mutation file declares what it depends on, and changing one recursively downs and re-ups it and everything that depends on it — is well suited to this "runs on every reload" model, since a run against an already-applied schema is a cheap no-op. A typical setup:
This repo's own dev database uses it locally :
just test-db-migrate # dmut apply against the dev database
just test-db-fresh # tear down, bring up Postgres, migrate, and seed in one shot
ghcr.io/rel-server/rel-dmut bundles dmut alongside rel in one image and presets reload.cmd
to run it against /sql (override with DMUT_MUTATIONS_PATH) — see Docker
deployment.