Browse Source
Reverts the shape of the previous commit without reverting its finding. The pull keeps its own unit -- it can be long, and its duration has no business inside the container's start time -- and the container keeps After= on it, so the pull still runs first on a boot where the network is there. What changes is the strength of the dependency. Measured on the radio head rather than assumed, because the obvious fix does not work: Restart=on-failure on the .image unit makes the PULL converge and leaves the container inactive for good. A failed dependency is never retried -- the dependent job dies at the first failure, and the later successful restart of the required unit does not re-trigger it. Upholds= on the pull unit does pick the container up, at the price of a container that can no longer be stopped on its own, and it still leaves the container down for as long as the registry is unreachable even though the image is right there. So: Image= names the reference, which is what keeps quadlet from generating the Requires=, and the container declares Wants= + After= on the pull unit itself. The pull unit gains Restart=on-failure with StartLimitIntervalSec=0, so a machine that boots without a network ends up with the image instead of a stale one, and PartOf=zwave-js-ui.target so stopping the target leaves nothing retrying. Verified on the target, booted with ghcr.io pointed at 127.0.0.1: the container starts from local storage and reports healthy while the pull unit retries, then the pull converges on its own after two restarts once resolution is restored, and nothing is left in systemctl --failed. The image reference now appears in both files, on purpose. The alternative -- a drop-in resetting the generated Requires= -- has to restate the container's other requirements and silently drops any a later edit adds. That trap is worse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>pull/11/head
3 changed files with 101 additions and 26 deletions
@ -0,0 +1,34 @@ |
|||
[Unit] |
|||
Description=podman pull ghcr.io/zwave-js/zwave-js-ui |
|||
Documentation=https://zwave-js.github.io/zwave-js-ui/ |
|||
|
|||
# Keep trying. A machine whose network arrives after it does -- a PoE port whose |
|||
# switch takes a minute to forward, an uplink that comes back after the machine -- |
|||
# fails this pull once, twenty-six seconds into the boot, and a oneshot that |
|||
# failed once never runs again. Measured on the radio head: network-online.target |
|||
# was reached at boot+26s and the DHCP lease only landed at boot+72s. |
|||
# |
|||
# StartLimitIntervalSec=0 is what makes the retry unlimited: the default start |
|||
# limit (5 attempts in 10 s) turns the unit "failed" for good after 15 seconds of |
|||
# a network that needs a minute. |
|||
StartLimitIntervalSec=0 |
|||
|
|||
# Stopping the service target stops the pull with it, so `systemctl stop |
|||
# zwave-js-ui.target` leaves nothing retrying behind. |
|||
PartOf=zwave-js-ui.target |
|||
|
|||
[Image] |
|||
# Multi-architecture manifest (amd64 + arm64, verified 2026-09-26 on tag 11 -> |
|||
# 11.24.1), so the cookbook installs on an aarch64 host as well as on the x86_64 |
|||
# radio head. The tag is the major version: Z-Wave JS UI ships the zwave-js |
|||
# driver and its Z-Wave JS Server, whose schema version is what Home Assistant |
|||
# negotiates. A major bump is the one that can break that handshake, so it is |
|||
# the one an operator has to opt into. |
|||
# |
|||
# THIS REFERENCE IS ALSO IN zwave-js-ui.container, on purpose, and the two must |
|||
# be changed together. The reason is in the container file and in the README. |
|||
Image=ghcr.io/zwave-js/zwave-js-ui:11 |
|||
|
|||
[Service] |
|||
Restart=on-failure |
|||
RestartSec=60 |
|||
Loading…
Reference in new issue