Hot-replace a script safely
To replace a running thing with a new version, append a fresh create
with the new script under the same <kind>.<name>:
# Replace the running 'log' service with an updated pipeliner#'{ run: {|| ^tail -F /tmp/log.txt | lines | each {|l| $"[v2] ($l)" } }}'# | .append xs.service.log.createThe runtime kills the old task, emits xs.service.log.replaced, and starts
the new one. A new xs.service.log.active follows.
What happens if the new script is broken?
The runtime never leaves you in an empty state because of a typo. The
algorithm keeps the last known-good version (the one that emitted active)
in a separate compaction slot.
If the new script fails to parse:
- The runtime emits
xs.service.log.invalid(with the parse error inmeta.reason) instead ofactive. - Live behaviour depends on the kind:
- Service / action: the previous (good) version keeps running. The replacement attempt is rejected; nothing changes.
- Actor: the running actor already exited on seeing the new
create(per the actor protocol). The dispatcher then re-spawns a fresh instance from the last known-goodcreateso the system isn’t left empty.
- On the next restart of xs, compaction sees the same picture and starts
the last known-good
create, not the broken one.
Inspecting the log
You can verify the fallback happened by looking for the lifecycle frames:
.cat -T xs.service.log.* | last 5Look for the invalid frame (the rejected attempt) and the most recent
active (the version that’s actually running).
Related
- Compaction algorithm: the two-slot algorithm and its rules.
- Lifecycle design: why the fallback exists.