release(v1.7.20-alpha): stop auto-apply scheduler killing the service

The 3AM auto-update path called std::process::exit(0) immediately
after apply_update returned. apply_update had already spawned a 2s-
delayed systemctl restart, but exit(0) killed the runtime before that
spawned task could run — and the unit's Restart=on-failure does not
trigger on a clean exit 0, so the service stayed dead until someone
SSH'd in and started it manually (.253 hit this today).

Scheduler now returns from the task without killing the process;
apply_update's existing restart path (same one the UI's Install
Update button uses) brings the new version up cleanly.

Also hardens the ISO CI: the AIUI inclusion step now falls back to
extracting from the newest release tarball if the runner's cached
/opt/archipelago/web-ui/aiui path is missing, so a reprovisioned
runner can't silently ship a frontend tarball without AIUI. The ISO
build step also sanity-checks the binary exists before invoking the
builder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian 2026-04-21 04:33:11 -04:00
parent 4e2c6d210b
commit 40f76013dc
5 changed files with 62 additions and 11 deletions

View File

@ -74,12 +74,38 @@ jobs:
- name: Include AIUI if available
run: |
if [ -d "/opt/archipelago/web-ui/aiui" ] && [ -f "/opt/archipelago/web-ui/aiui/index.html" ]; then
mkdir -p web/dist/neode-ui/aiui
cp -r /opt/archipelago/web-ui/aiui/* web/dist/neode-ui/aiui/
echo "AIUI included from /opt/archipelago/web-ui/aiui/"
# AIUI (the Claude chat sidebar) lives outside the Vue build
# and must be copied into the frontend dist BEFORE packaging,
# otherwise OTA-tarball upgrades silently strip it from nodes
# in the field. Try in order: cached on runner, then the
# newest release tarball in this repo's releases/ dir as a
# fallback so a freshly-provisioned runner still gets AIUI.
AIUI_SRC=""
if [ -f "/opt/archipelago/web-ui/aiui/index.html" ]; then
AIUI_SRC="/opt/archipelago/web-ui/aiui"
elif [ -f "$HOME/archy/web/dist/neode-ui/aiui/index.html" ]; then
AIUI_SRC="$HOME/archy/web/dist/neode-ui/aiui"
else
echo "WARNING: AIUI not found on build server — ISO will not include AIUI"
LATEST_FRONTEND=$(ls -t releases/v*/archipelago-frontend-*.tar.gz 2>/dev/null | head -1)
if [ -n "$LATEST_FRONTEND" ]; then
echo "Extracting AIUI from $LATEST_FRONTEND (runner cache miss)"
TMP=$(mktemp -d)
tar xzf "$LATEST_FRONTEND" -C "$TMP" ./aiui 2>/dev/null || true
if [ -f "$TMP/aiui/index.html" ]; then
AIUI_SRC="$TMP/aiui"
fi
fi
fi
if [ -n "$AIUI_SRC" ]; then
mkdir -p web/dist/neode-ui/aiui
cp -r "$AIUI_SRC/"* web/dist/neode-ui/aiui/
echo "AIUI included from $AIUI_SRC ($(du -sh web/dist/neode-ui/aiui | cut -f1))"
else
echo "FAIL: AIUI not found anywhere (runner cache + release tarballs)"
echo " checked: /opt/archipelago/web-ui/aiui"
echo " \$HOME/archy/web/dist/neode-ui/aiui"
echo " releases/v*/archipelago-frontend-*.tar.gz"
exit 1
fi
- name: Configure root podman for insecure registry
@ -93,7 +119,15 @@ jobs:
run: |
cd image-recipe
export ARCHIPELAGO_BIN="$(pwd)/../core/target/release/archipelago"
ls -la "$ARCHIPELAGO_BIN" || echo "WARNING: binary not found"
if [ ! -x "$ARCHIPELAGO_BIN" ]; then
echo "FAIL: backend binary missing or not executable at $ARCHIPELAGO_BIN"
exit 1
fi
BIN_VERSION=$(strings "$ARCHIPELAGO_BIN" | grep -oE 'archipelago [0-9]+\.[0-9]+\.[0-9]+(-[a-z]+)?' | head -1 || true)
EXPECTED=$(grep '^version' ../core/archipelago/Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
echo "Binary: $ARCHIPELAGO_BIN ($(du -h "$ARCHIPELAGO_BIN" | cut -f1))"
echo "Embedded version string: ${BIN_VERSION:-unknown}"
echo "Expected version (Cargo.toml): $EXPECTED"
sudo -E UNBUNDLED=1 DEV_SERVER=localhost BUILD_FROM_SOURCE=0 \
ARCHIPELAGO_BIN="$ARCHIPELAGO_BIN" \
./build-auto-installer-iso.sh

2
core/Cargo.lock generated
View File

@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "archipelago"
version = "1.7.19-alpha"
version = "1.7.20-alpha"
dependencies = [
"anyhow",
"archipelago-container",

View File

@ -1,6 +1,6 @@
[package]
name = "archipelago"
version = "1.7.19-alpha"
version = "1.7.20-alpha"
edition = "2021"
description = "Archipelago Bitcoin Node OS - Native backend"
authors = ["Archipelago Team"]

View File

@ -882,9 +882,15 @@ pub async fn run_update_scheduler(data_dir: std::path::PathBuf) {
debug!("Update scheduler: apply failed: {}", e);
continue;
}
info!("Update scheduler: update applied, restart needed");
// Signal for service restart (systemd will handle via exit code)
std::process::exit(0);
info!("Update scheduler: update applied, restart scheduled by apply_update");
// apply_update has already spawned a 2s-delayed
// `systemctl restart archipelago`. Don't call
// std::process::exit here — that kills the runtime
// before the spawned restart task runs, and since
// the unit is Restart=on-failure a clean exit(0)
// leaves the service dead. Fall through; the
// scheduled restart will bring us back cleanly.
return;
}
Ok(_) => {
debug!("Update scheduler: no update available");

View File

@ -180,6 +180,17 @@ init()
</button>
</div>
<div class="overflow-y-auto flex-1 min-h-0 space-y-6 pr-1">
<!-- v1.7.20-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">
<span class="text-xs font-mono px-2 py-0.5 rounded bg-orange-500/20 text-orange-300">v1.7.20-alpha</span>
<span class="text-xs text-white/40">Apr 21, 2026</span>
</div>
<div class="space-y-3 text-sm text-white/80 pl-3 border-l border-white/10">
<p>Fixed a critical bug where nodes on the automatic daily-update schedule could end up offline after their nightly update. The scheduler was killing the service a moment too early, before the built-in restart handler had a chance to bring the new version back up leaving the node dead until someone SSH'd in and started it manually. The scheduler now hands off cleanly to the same restart path the 'Install Update' button uses, so auto-applied updates come back online on their own.</p>
<p>Applies to any node configured for 'Check &amp; Apply Daily' no change required on your end, the fix ships with this update.</p>
</div>
</div>
<!-- v1.7.19-alpha -->
<div>
<div class="flex items-center gap-2 mb-3">