Fix web UI hangs, stalls and lost config edits #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/web-ui-hangs"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this PR does
Fixes the ways the device web UI could hang, stall or wedge under real-world timing: daemon restarts that outlast the page's wait, apply calls timing out on changes that still land, threads pinned by stalled clients or hung plugins, and a lost-update race on
config.toml. It also points CLAUDE.md at this PR template.Checklist
make lint(ansible--syntax-check,yamllint,shellcheck --severity=error). The Lint workflow runs this on the PR.make test(thekestrel_pipytest suite). The Test workflow runs this on the PR..envfiles, real names, personal emails, MAC addresses, device serials, or GPS coordinates — placeholders only.docs/, and the on-device operator guide (GUIDE_MDinkestrel_pi/userguide.py) where it applies.Release impact
kestrel_pipackage,plugins/*.py, systemd units, the journald drop-in, a lib script already in the engine'sLIB_SCRIPTS, or the CLI.config.txt/cmdline, kernel modules, the base image or partition size,builder/config.json,builder/config.yml, theMakefile,.forgejo/workflows/, a shipped config default (config.toml/default.conf), or a brand-new lib script.Changed install targets: the
kestrel_pipackage,config-setandplugins-ctl(both already inLIB_SCRIPTS), the CLI, and two units (kestrel-daemon.service,kestrel-plugins-apply@.service; the engine runsdaemon-reload).CLAUDE.mdanddocs/are not installed on the device.update_kind=autopicks app-layer correctly.Notes for review
Changes
on_unloadcalls run concurrently within one 25 s budget (Loader.unload_all), and a hung one is logged and abandoned.main()exits withos._exitafter the clean stop, so hook-pool threads stuck in a hook are no longer joined.TimeoutStopSec=40, and the restart-wait page polls for about 2 minutes (was about 40 s).RuntimeMaxSec50 s < client 55 s. The client has one overall deadline and returns on the one-line reply, instead of waiting for the helper to exit.capture disable/agent disablewrite config first, then stop with--no-block. Before, a helper killed mid-stop could leave capture stopped but still enabled. BT re-pair restarts onboarding with--no-block.on_webhookcall is still running, further calls to that plugin get a 503 instead of a new thread.systemctl is-activeprobes share one call.config.tomlis re-parsed only when its stat changes (callers get a copy), and/networksis cached until a store file changes.flockon.config.toml.lockbeside the config, inconfig-set.py, which every config writer goes through.Behaviour changes
kestrel capture disable/agent disablereturn before the service has finished stopping. The update engine is unaffected, because it uses plainsystemctl stop./etc/kestrel/.config.toml.lockfile is created on the first config write.on_unloaduses services orcontext.apply./run/kestrelon stop.Testing
on_unload, the apply client's line return and overall deadline, the stuck-webhook 503, the stalled-connection timeout against real werkzeug, the caches, the reconcile debounce and the config lock.🤖 Generated with Claude Code