Skip to navigation

Service

service manages whether a service is running, enabled, and masked, and how it reacts to notifications. Systemd is the built-in backend; plugins can add others. This example names systemd explicitly:

service "app" {
provider = "systemd"
name = "example-app"
ensure = "running"
enabled = true
masked = false
on_change = "reload_or_restart"
daemon_reload = "auto"
}
AttributeDefaultBehavior
provider"auto"Select a registered backend, or resolve one from target capabilities and declared priorities at compilation.
nameLabelNormalized by the selected backend. Systemd adds .service and rejects paths, option-like names, and other unit types.
ensureUnmanagedrunning or stopped; null or omission leaves activity unmanaged.
stateAliasLegacy spelling of ensure; cannot supply both.
enabledUnmanagedIndependent enablement boolean; rejected if the selected backend does not support it.
maskedUnmanagedIndependent mask boolean; rejected if the selected backend does not support it.
on_change"restart" if supported, else "none"Backend-supported choice of restart, strict reload, reload_or_restart, or none.
daemon_reload"auto" when a definition action exists, else "never"auto or never; explicit auto is rejected without backend support.

Null optional fields follow omission and default behavior. stopped means inactive; it does not delete, disable, or mask the unit. There is no service absent state.

Systemd convergence

Unmasking precedes enable/start; stop/disable precede masking. A masked unit needs masked = false before it can be started or enabled. Enabling static, generated, or transient units fails.

Missing, malformed, transitional, and unsupported states fail instead of being treated as absent. Canonical unit identities detect alias ownership conflicts, including a fresh check after definition changes. Default budget: two minutes. Systemd requires service.systemd.v1; other backends declare their required capabilities.

Refresh policy

reload is strict: failed or unsupported reload does not silently become a restart. Choose reload_or_restart if you want that fallback. none consumes notification work without a service mutation.

An inactive or explicitly stopped unit consumes refreshes without starting. A verified initial start consumes pending config refreshes without a redundant restart. Refresh is separate from ordinary desired-state convergence and has its own deadline.

Use meta { subscribe = [file.config] } or notify on the source to request refresh. Dependency ordering alone is insufficient.

Systemd daemon reload barrier

With auto, managed .service files and .service.d/*.conf files beneath /etc/systemd/system, /usr/lib/systemd/system, and /lib/systemd/system precede service work. Changes coalesce into one journaled systemd daemon-reload barrier. Systemd-reported stale definitions can also request it.

This is a shared prerequisite action, separately reported from service restart/reload. never disables the automatic barrier. Automatic reload also requires refresh.journal.v1.

Refresh intent and outgoing causal obligations are durable. Interruption can lead to repeated delivery; recovery explains the limits.

Plugin providers

Approved subprocess plugins can add backends with provider = "NAME" and a matching unlabelled child block for typed options. A child block for another provider fails validation. The normalized options, provider schema version, and implementation identity are pinned into the catalog and recovery digests.

provider = "auto" chooses the applicable backend with the highest declared priority using the compilation target’s capabilities. A tie or no applicable backend fails. With only built-ins installed, systemd is selected when its capability is available. Use an explicit provider when selection must remain fixed as installations change.

Backends declare supported fields, refresh modes, capabilities, normalized identity, physical ownership, affected paths, and optional shared definition actions. Rivet retains property comparisons, verification, notification coalescing, startup refresh consumption, and reporting. Omitted properties remain unmanaged; unsupported requested properties are rejected. Plugin definition actions use the same durable shared-action mechanism as systemd’s barrier.

To write a backend, see the SDK guide.