Skip to content

Observe NOTAM changes instead of polling on the main actor#11

Merged
RISCfuture merged 1 commit into
mainfrom
fix/performance-viewmodel-main-thread-faults
Jun 23, 2026
Merged

Observe NOTAM changes instead of polling on the main actor#11
RISCfuture merged 1 commit into
mainfrom
fix/performance-viewmodel-main-thread-faults

Conversation

@RISCfuture

Copy link
Copy Markdown
Contributor

Summary

Removes a 500ms main-actor SwiftData poll in BasePerformanceViewModel, part of the launch-time app hangs SF50-TOLD-26 / SF50-TOLD-20 (still active on 3.5.6: 19 App Hang Fully Blocked events on 3.5.6+47).

Background

These hangs are the main thread blocked in -[NSManagedObjectContext performBlockAndWait:]. setupRunwayNOTAMObservation ran a Task { @MainActor … } loop that, every 500ms for the lifetime of the takeoff/landing screen, faulted the selected runway's NOTAM through the main ModelContext to detect edits. That recurring main-thread fault contends with the persistent store coordinator and stalls the main thread under load.

Change

Replace the poll with withObservationTracking — the same Observation mechanism the NOTAM editing views already rely on:

  • The main actor reads the NOTAM only when it actually changes, never on a timer.
  • The observation re-arms itself after each change.
  • A generation token (notamObservationToken) invalidates the observation registered for a previous runway selection, so stale chains from rapid runway switches bail out.

Behavior is preserved: editing or clearing a NOTAM still re-initializes the model and recalculates.

Testing

  • swift format lint --strict and swiftlint --strict clean.
  • Built the SF50 TOLD scheme for the iOS 26.5 iPhone 16 simulator — succeeds.
  • Simulator end-to-end (UI-TESTING seed, KOAK / runway 28R):
    • Baseline performance computes on airport/runway selection (Ground Run 1,763 ft, Total Distance 2,560 ft).
    • Adding an obstacle NOTAM recalculates — "Adjustments and Operational Notes…" (1) becomes "Adjustments and Operational Warnings…" (2).
    • Clearing the NOTAM recalculates back to "Notes" (1).
    • Confirms the observation fires on both NOTAM add and remove, with no crash or hang.

The hang reduction itself is a production/contention effect not reproducible on the simulator; this verifies the replacement preserves the recalc-on-NOTAM-change behavior.

🤖 Generated with Claude Code

`setupRunwayNOTAMObservation` ran a 500ms `Task { @mainactor … }` loop for
the lifetime of the takeoff/landing screen, faulting the selected
runway's NOTAM through the main `ModelContext` twice a second to detect
edits. That recurring main-thread SwiftData access contends with the
persistent store coordinator and contributes to the launch-time
`performBlockAndWait` hangs (SF50-TOLD-26/-20), which remain active on
3.5.6.

Replace the poll with `withObservationTracking` — the same Observation
mechanism the NOTAM editing views already use. The main actor now reads
the NOTAM only when it actually changes, never on a timer, and the
observation re-arms itself after each change. A generation token
invalidates the observation registered for a previous runway selection.

Refs SF50-TOLD-26, SF50-TOLD-20.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RISCfuture RISCfuture force-pushed the fix/performance-viewmodel-main-thread-faults branch from 5d1d553 to 7c024e3 Compare June 23, 2026 17:25
@RISCfuture RISCfuture merged commit ab77b32 into main Jun 23, 2026
5 checks passed
@RISCfuture RISCfuture deleted the fix/performance-viewmodel-main-thread-faults branch June 23, 2026 17:26
RISCfuture added a commit that referenced this pull request Jun 30, 2026
Reduce the main-actor SwiftData contention behind the launch-time
performBlockAndWait hangs (SF50-TOLD-26/-20), and quiet transient Sentry
noise:

- Stop NavDataLoaderViewModel's perpetual 0.5s state poll once nav data is
  loaded, so a returning user does zero background SwiftData work after
  launch (#10).
- Observe runway NOTAM changes with withObservationTracking instead of a
  500ms main-actor poll for the lifetime of the takeoff/landing screen
  (#11).
- Treat TLS handshake failures (secureConnectionFailed) as transient and
  stop double-reporting weather-fetch network errors to Sentry (#9).

Refs SF50-TOLD-26, SF50-TOLD-20, SF50-TOLD-2D, SF50-TOLD-21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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