fix(lifecycle): let user app actions wait out background lock holds #165
Closed
ssmithx
wants to merge 0 commits from
fix/lifecycle-lock-wait into main
pull from: fix/lifecycle-lock-wait
merge into: :main
:main
:pr/feat/first-install-owner-network-20261112
:pr/demo-intro-ux-polish
:docs/security-audit-2.0.3-alpha
:docs/fips-compute-market-proposal
:feat/routstr-fips-llama
:docs/ui-uat-pr-rule
:fix/routstr-xcashu-change
:fix/lifecycle-lock-wait
:fix/btcpay-db-password
:feat/podsteadr-app
:feat/qortal-app
:fix/quadlet-iec-memory-limits
:feat/podsteadr-app-package
:arm64-pi-test
:feat/nostr-vpn-seller-app
:work/terminal-developer-spec-20261009
:feat/justworks-integration-review
:conduit-market-archyapp
:fix/gitea-portainer-20260930
:fix/app-install-lifecycle-20260930
:fix/filebrowser-purchase-filing
:fix/ecash-paid-download-v2-keyset
:fix/paid-content-payment-not-lost
:fix/mint-error-detail-swallowed
:investigate/framework-lnd-startup
:fix/minibits-already-redeemed
:cuprate-fixes
:feature/dojobay-app
:fix/bitcoin-core-tor-service-name
:docs/openwrt-gateway-setup
:cuprate-cpu-fix
:fix/cuprate-explicit-logging-levels
:companion/session-2026-08-31
:companion/0.5.28-deploy-handoff
:companion/0.5.28-ship
:companion/0.5.28
:app-bumps-mirror-pending
:cuprate-archyapp
:docs/todo-list
:companion/0.5.27-version-meta
:companion/0.5.27-ship
:companion/0.5.27-clipboard-qr-restart
:ux-at-last
:fix/mesh-send-content-inline-federation-fallback
:cashu-error-messages
:gsd/phase-13-aiui-functional-conversational-node-control-and-content-surf
:rotate-release-root
:chore/aiui-monorepo-migration
:wip/phase-13-p13-02
:wip/phase-13-p13-01
:fix/bitcoin-conf-conflict-crash-loop
:demo-build
:archy-hwconfig
:openwrt-enhancements
:a3-10-endpoint-fallback
:public-prelaunch
:release/1.7.115-prep
:fix/web-listener-ipv6
:fips-companion-5g-hardening
:fix/connection-accept-deadlock
:fix/demo-images-path-filter
:fix/companion-autologin-replay-intro
:networking-profits-dashboard
:identities-mobile-polish
:companion-qr-scan-fix
:companion-qr-pairing
:intro-reliability-video-perf
:login-bg-continuity
:audio-bottom-bar
:demo-intro-every-visit
:intro-entrance-fixes
:cloud-feedback-demo-content
:cloud-tabs-search
:ark-wallet-ui-demo
:demo-nginx-app-assets
:demo-ui-fixes
:ark-wallet-barkd
No Reviewers
Labels
Clear labels
companion-agent
queued
roadmap
waiting-external
Companion-app agent's handover list (node-side parts tracked separately)
Triaged, next in this session's queue after current release work
Feature/effort item, deliberately unscheduled — needs scoping + a slot, not a fix today
Waiting on a person outside this session (tester, operator)
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: lfg2025/archy#165
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
User Start / Stop / Restart / Install / Uninstall actions were refused with "An app lifecycle operation is active; retry when it completes".
The background reconcile pass holds the app-lifecycle
flockfor its whole walk over every loaded manifest. On a 2-CPU test node that was 20–21s per pass, every ~50s, even when idle. Health recovery also holds it during auto-restarts. User-facing handlers tried the lock once withLOCK_NB, so any action that landed during a hold failed immediately.Fix (4 commits)
Guard::acquire_waiting/acquire_withinpoll every 200ms. Background acquirers (reconcile, health monitor, crash recovery) keep try-once semantics and retry next cycle.flockerrors other thanEWOULDBLOCKare now reported as themselves.install/update/uninstalltake the lock inside their spawned task, after the RPC has answered, so they useBACKGROUND_LOCK_WAIT(5 min). An uninstall issued 13s after an Archipelago restart had previously given up while the first reconcile pass held the lock.USER_LOCK_WAIT(10s, inside the UI's 15s RPC timeout), which keeps errors synchronous in the common case. If the lock still isn't free, the command is accepted: state flips immediately, and the background task waits (5 min, as a registered waiter), runs the samerequire_clear/require_unheldchecks, then does the work. A failure there reverts the state and is logged, matching install/uninstall.Tests
user_commands_wait_out_a_short_background_hold,user_commands_give_up_when_the_hold_outlasts_the_wait,waiting_command_is_visible_only_while_it_waits,reconcile_pass_yields_to_a_waiting_command_and_resumes_there,busy_lifecycle_lock_defers_the_command_to_its_background_task.main; they needscripts/test-backend-isolated.sh.Verified on a real node
run-gate.sh, 5 iterations, on-node), with suites for apps not installed on that node excluded: 5/5 green, 155 passed, 0 failed, 0 refused commands. Before commits 3–4 the same run failed 2 of 5 iterations onfilebrowser:stop-rpc.🤖 Generated with Claude Code
Reconciled against canonical ngit review: fix(lifecycle): let user app actions wait out background lock holds is applied.
This PR's exact head
ee40ce8f9c329a155f1919cf20891944e39fb758is already an ancestor of accepted main1a4ea15df9c8800b6d288277d2839c7b93662ff7, which matches on ngit and Gitea. The existing review fixes and commit history are preserved.Closing the redundant Gitea PR record because its contribution has already been integrated through ngit. No second merge or history rewrite is being performed. Artifact publication and installed-device acceptance remain separate from this source-review disposition.
Pull request closed