Skip to content

fix: make lifecycle lock acquisition atomic - #529

Merged
GhostXia merged 6 commits into
mainfrom
codex/issue-478-lock-atomicity
Aug 8, 2026
Merged

fix: make lifecycle lock acquisition atomic#529
GhostXia merged 6 commits into
mainfrom
codex/issue-478-lock-atomicity

Conversation

@GhostXia

@GhostXia GhostXia commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Acquire an OS-level exclusive lock on engine-instance.lock before lifecycle read/probe/spawn/write work, and retain the lock inode when clearing its owner record.
  • Coordinate async sidecar startup and Tauri shutdown through one state mutex plus the startup JoinHandle, so exit cannot race a half-published child/owner pair or leave a newly spawned engine orphaned.
  • Preserve the durable owner record when stopping the child fails, allowing the next launch to identify and recover the owned process.
  • Update the packaged Windows smoke to verify a persistent empty lock sentinel and a complete second launch/shutdown cycle.

The original read → probe → spawn → write sequence allowed concurrent shells to make the same decision. The follow-up audit also found that detached startup could overlap ExitRequested, exposing spawn/publish/cleanup windows. Both paths are now serialized without aborting a spawned-but-unpublished child.

Refs #478

Validation

  • cargo test --manifest-path ui/src-tauri/Cargo.toml --locked — 25 passed, including a real child-process lock handshake and deterministic spawn/shutdown transaction tests.
  • cargo clippy --manifest-path ui/src-tauri/Cargo.toml --all-targets --locked -- -D warnings — passed.
  • cargo fmt --all -- --check — passed.
  • PowerShell AST parse of deploy/windows-webui/smoke-desktop-ui.ps1 — passed.
  • git diff --check — passed.
  • The existing build.rs prerequisite requires ui/src-tauri/binaries/airp-core-x86_64-pc-windows-gnu.exe. Local Rust validation used an empty temporary placeholder that was removed afterward; no binary asset is committed.
  • Unix/macOS native runtime evidence is not available in this environment. This PR does not claim complete cross-platform verification; the v0.0.5 release gate here is the hosted packaged Windows smoke.

Audit status

Independent audit was performed before the lifecycle fix and repeated after each blocking test correction. The final audit found no remaining blocking issue and approved the change for CI. Formal repository audit remains required after the PR leaves draft; this PR must not merge until that audit and every required check pass.

Summary by CodeRabbit

  • Bug Fixes

    • Improved desktop UI startup and shutdown reliability.
    • Prevented multiple instances from using the same configured port.
    • Added validation to ensure lifecycle ownership matches the active UI instance.
    • Improved cleanup after failed launches and shutdowns.
  • Enhancements

    • Desktop UI can now be launched again after a graceful shutdown.
    • Lifecycle state is safely retained and cleared during shutdown.
    • Readiness checks and background tasks now stop promptly when shutting down.
  • Tests

    • Expanded smoke coverage for relaunching, lock ownership, cleanup, and failure scenarios.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@GhostXia, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 08af910b-c951-47a3-94c1-dfc70c6f586c

📥 Commits

Reviewing files that changed from the base of the PR and between 0a13383 and 12bd1e2.

📒 Files selected for processing (3)
  • deploy/windows-webui/smoke-desktop-ui.ps1
  • ui/src-tauri/Cargo.toml
  • ui/src-tauri/src/lifecycle.rs
📝 Walkthrough

Walkthrough

The change adds persistent OS-level lifecycle locking, coordinates sidecar startup and shutdown through shared state, preserves lock ownership during failures, stops asynchronous work during shutdown, and expands the Windows smoke test to validate lock reuse across two launches.

Changes

Lifecycle lock coordination

Layer / File(s) Summary
Persistent lock guard and cleanup
ui/src-tauri/src/lifecycle.rs
LockGuard and acquire_lock provide exclusive lock ownership. Owner records are updated or cleared in place while the lock-file inode remains.
Coordinated startup and shutdown
ui/src-tauri/src/main.rs
Shared sidecar state coordinates startup, shutdown, cancellation, published ownership, and conditional cleanup.
Transactional spawn and cancellation
ui/src-tauri/src/main.rs
Sidecar publication occurs after successful setup. Readiness, navigation, probes, and token renewal stop when shutdown begins. Tests cover serialization and cleanup behavior.
Smoke-test lock reuse validation
deploy/windows-webui/smoke-desktop-ui.ps1
The smoke test validates live ownership, empty shutdown records, second-launch reuse, and failure cleanup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DesktopLauncher
  participant LifecycleLock
  participant Sidecar
  participant SidecarState
  DesktopLauncher->>LifecycleLock: acquire_lock
  LifecycleLock-->>DesktopLauncher: LockGuard
  DesktopLauncher->>Sidecar: start and probe
  Sidecar-->>DesktopLauncher: readiness
  DesktopLauncher->>SidecarState: publish child and instance_id
  DesktopLauncher->>Sidecar: terminate published child
  Sidecar-->>DesktopLauncher: successful termination
  DesktopLauncher->>LifecycleLock: clear owner record
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: making lifecycle lock acquisition atomic.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-478-lock-atomicity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

GhostXia commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

独立审计补充:hosted Windows run 31253089432 中,Portable Windows WebUI 的构建、进程 smoke 与浏览器 smoke 均通过,但桌面 UI smoke 在退出后于 deploy/windows-webui/smoke-desktop-ui.ps1:114engine instance lock was not cleaned up after UI exit。该结果实证 async startup ↔ RunEvent::Exit 生命周期竞态/锁清理阻塞。此 finding 超出本低风险切片范围;PR 继续保持 draft,不合并,直至更高性能模型完成取消/Join/锁所有权设计并补跨平台证据。

GhostXia commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

审计更正:run 31253089432 的直接失败原因不是 async race 实证。该 smoke 已等待 engine ready;PR 又把退出清理从删除文件改为 LockGuard::clear()(保留空 inode),而脚本仍以 Test-Path 要求路径消失,因此正常退出也会确定性失败。此前评论中“该 run 实证竞态”的表述撤回。真实 startup↔Exit 竞态仍由代码时序独立成立(detached task、child/instance_id 分离发布、cleanup 遇 startup guard WouldBlock),将按单一状态锁、协作取消、等待 startup JoinHandle 后清理来修复;kill 失败时必须保留 owner record。

@GhostXia

GhostXia commented Aug 8, 2026

Copy link
Copy Markdown
Owner Author

Implemented and independently re-audited the startup/shutdown race fix in 0a13383. Local evidence: 25/25 Rust tests (including real child-process locking and deterministic transaction tests), clippy -D warnings, fmt, PowerShell AST, and diff-check all pass. The earlier hosted smoke failure was a stale assertion requiring lock-file deletion; the updated contract intentionally retains an empty inode and now verifies two packaged launch/shutdown cycles. Unix/macOS native behavior remains unverified and is not claimed. Keeping this draft until the current CI run is green, then formal audit will be triggered.

@GhostXia
GhostXia marked this pull request as ready for review August 8, 2026 12:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/windows-webui/smoke-desktop-ui.ps1`:
- Around line 58-75: In the record validation flow, move the
[string]::IsNullOrWhiteSpace($instanceId) check before
[Guid]::Parse($instanceId), preserving the existing dedicated error message for
missing or empty instance_id values and validating the GUID only afterward.

In `@ui/src-tauri/src/lifecycle.rs`:
- Around line 22-23: Add a rust-version = "1.89" declaration for the
ui/src-tauri crate or its workspace so File::try_lock and TryLockError require
the supported toolchain. Update the static Rust toolchain pin SHA to the
corresponding CI stable version, preserving the existing toolchain
configuration.
- Around line 466-480: Update startup_lock_serializes_concurrent_claims to
acquire the lock from a separate child process rather than using two descriptors
in the same process, while preserving the WouldBlock assertion and
reclaimability check after the child exits. Reuse the existing dedicated
child-process locking test or its established process-spawn mechanism instead of
relying on same-process acquire_lock calls.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 968bbb7d-7ea7-4d93-aedb-5bf7ca448321

📥 Commits

Reviewing files that changed from the base of the PR and between 90a996f and 0a13383.

📒 Files selected for processing (3)
  • deploy/windows-webui/smoke-desktop-ui.ps1
  • ui/src-tauri/src/lifecycle.rs
  • ui/src-tauri/src/main.rs

Comment thread deploy/windows-webui/smoke-desktop-ui.ps1
Comment thread ui/src-tauri/src/lifecycle.rs
Comment thread ui/src-tauri/src/lifecycle.rs Outdated
@GhostXia
GhostXia merged commit 6b4c85b into main Aug 8, 2026
8 checks passed
@GhostXia
GhostXia deleted the codex/issue-478-lock-atomicity branch August 8, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant