release(v1.7.32-alpha): fix frontend tarball layout + mDNS shutdown hang

- HOTFIX: v1.7.31-alpha's frontend tarball was packaged with a
  `neode-ui/` top-level directory instead of the flat layout v1.7.30
  and earlier used. Nodes that applied v1.7.31 ended up with
  `/opt/archipelago/web-ui/neode-ui/index.html` instead of
  `/opt/archipelago/web-ui/index.html`, and nginx returned 403/500.
  v1.7.32's tarball is built with `tar -C web/dist/neode-ui .` so
  files land directly at web-ui root. Broken nodes auto-heal on this
  update (web-ui dir is replaced).
- transport/lan.rs: add Drop impl that calls ServiceDaemon::shutdown()
  on the mdns_sd daemon. Without this the OS thread it spawns, plus
  the blocking `receiver.recv()` task, keep the tokio runtime alive
  past SIGTERM — long enough for systemd's TimeoutStopSec to SIGKILL
  the service and mark it Failed. Was visible on every update:
  "shut down cleanly" logged, then 15s later systemd forcibly kills.
- main.rs: after logging "Archipelago shut down cleanly", call
  `std::process::exit(0)` explicitly. Belt-and-suspenders against
  any future non-daemon thread creeping in (reqwest resolver pool,
  etc.) and causing the same SIGKILL regression.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian 2026-04-22 03:52:22 -04:00
parent 682b93f2d6
commit 974fce5870
4 changed files with 24 additions and 3 deletions

2
core/Cargo.lock generated
View File

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

View File

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

View File

@ -229,5 +229,14 @@ async fn main() -> Result<()> {
crash_recovery::remove_pid_marker(&config.data_dir).await;
info!("Archipelago shut down cleanly");
Ok(())
// Hard-exit after logging. All business state is persisted by now
// (connections drained, PID marker removed, disk flushes done via
// tokio::fs awaits). Letting tokio try to drop the runtime instead
// can stall for 15s+ on non-daemon OS threads we don't directly
// own (mdns_sd daemon, reqwest resolver pool, etc.) — long enough
// for systemd's TimeoutStopSec to SIGKILL us and mark the service
// Failed, which makes an otherwise-successful update look like a
// crash in `systemctl status`.
std::process::exit(0);
}

View File

@ -160,6 +160,18 @@ impl LanTransport {
}
}
impl Drop for LanTransport {
// The mdns_sd daemon runs on its own OS thread and the browse
// listener task blocks on a sync channel. Without this call both
// keep the process alive past SIGTERM, long enough for systemd to
// SIGKILL us — which makes a normal update look like a crash.
fn drop(&mut self) {
if let Some(daemon) = self.daemon.take() {
let _ = daemon.shutdown();
}
}
}
impl NodeTransport for LanTransport {
fn kind(&self) -> TransportKind {
TransportKind::Lan