Skip to content

fix(macos): run GatewayConnectionManager health check loop off @MainActor#26082

Merged
tkheyfets merged 2 commits into
mainfrom
devin/lum-916-move-gatewayconnectionmanager-health-check-off-mainactor-to
Apr 17, 2026
Merged

fix(macos): run GatewayConnectionManager health check loop off @MainActor#26082
tkheyfets merged 2 commits into
mainfrom
devin/lum-916-move-gatewayconnectionmanager-health-check-off-mainactor-to

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Moves the 15 s health check loop to a detached .utility task so its Task.sleep scheduling and between-check work no longer occupy @MainActor; only performHealthCheck() and the update-timeout cleanup (which mutate @Published state) hop back to main via MainActor.run. This removes periodic main-actor pressure that was contributing to app hangs under memory pressure without changing resolveConnection() or the rest of the network stack that triggered the earlier revert of #21695.

Closes LUM-916



Open with Devin

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

@vex-assistant-bot vex-assistant-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✦ Vex Review — PR #26082 (LUM-916)

Good approach — moving the 15s health check loop to Task.detached(.utility) with explicit MainActor.run hops for state reads (isUpdateInProgress, shouldReconnect) is clean and correct. The guard !Task.isCancelled after sleep is a good addition.

Same two concerns as PR #26081:

  1. Overlap with #26081 (LUM-914): That PR offloads the inner performHealthCheck() work. If both merge, you get nested detached tasks. I'd suggest either: (a) merge #26082 first (outer loop off-main), then #26081 becomes unnecessary since performHealthCheck() is already called from a non-main context, or (b) merge #26081 first and skip #26082. The outer loop's Task.sleep isn't expensive enough on @MainActor to justify detaching by itself — it's the HTTP work inside that causes hangs.

  2. Rebase needed: PR #25496 (merged today) migrated this class to @Observable. Both PRs should rebase to verify no semantic conflicts.

Recommendation: If you want both fixes, merge #26082 first (broader fix), then evaluate if #26081's inner detach is still needed.

devin-ai-integration Bot and others added 2 commits April 16, 2026 19:45
The 15-second health check loop previously ran as a Task { @mainactor ... }
so the while-loop, Task.sleep scheduling, and error handling all occupied
the main actor. Under memory pressure this periodic work contributes to
app hangs (LUM-914 recorded a ≥2000ms hang attributed to this loop on a
device with ~131MB free RAM).

Change the loop to a detached task at .utility priority and hop to
@mainactor only for the state reads (isUpdateInProgress,
healthCheckInterval, shouldReconnect) and the update-timeout cleanup
that mutates @published properties. performHealthCheck() itself stays
@mainactor so all @published writes and cached-assistant reads remain on
main — no new data races, no changes to resolveConnection() or the rest
of the network stack that triggered the earlier revert of #21695.

Refs: WWDC25 Embracing Swift concurrency
(https://developer.apple.com/videos/play/wwdc2025/268/),
Task.detached(priority:), MainActor.run.

Closes LUM-916

Co-Authored-By: tkheyfets <timur@vellum.ai>
Co-Authored-By: tkheyfets <timur@vellum.ai>
@devin-ai-integration devin-ai-integration Bot force-pushed the devin/lum-916-move-gatewayconnectionmanager-health-check-off-mainactor-to branch from b747fa1 to 7b4cfad Compare April 16, 2026 19:46
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

Rebased on main (which now includes #25496's @Observable migration) — no semantic conflicts. The MainActor.run hops are still correct because the class is @Observable @MainActor; @Observable changes the observation mechanism but not isolation, so off-main reads of isUpdateInProgress / shouldReconnect still require the hop. Updated inline comments to say "observable state" instead of the stale "@published state".

On the overlap with #26081: leaving coordination to the author of that PR, but agree that once this one merges the inner detach becomes redundant.

@tkheyfets tkheyfets merged commit 29afcaa into main Apr 17, 2026
7 checks passed
@tkheyfets tkheyfets deleted the devin/lum-916-move-gatewayconnectionmanager-health-check-off-mainactor-to branch April 17, 2026 14:02
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