Skip to content

PluginWidgetManifest.write: move blocking I/O off the main thread#2

Open
imaznation wants to merge 1 commit into
kemalandic:mainfrom
imaznation:proposal/plugin-manifest-off-main
Open

PluginWidgetManifest.write: move blocking I/O off the main thread#2
imaznation wants to merge 1 commit into
kemalandic:mainfrom
imaznation:proposal/plugin-manifest-off-main

Conversation

@imaznation
Copy link
Copy Markdown

Summary

PluginWidgetManifest.write() does file I/O (JSON encoding + atomic write) synchronously, and was being called from main-actor code paths during startup and on widget config changes. On slow disks or under contention the write can stall the main runloop long enough to be perceptible.

Fix

Hop the disk I/O onto a background queue. The encode step (Sendable JSON) runs there, and the manifest update closure on the main actor only flips a published flag once the write completes. No behavior change for callers — the function signature stays the same; what changes is which thread the bytes hit disk on.

Notes

Pure plumbing fix, no API surface change. Companion to the BluetoothService off-main fix (#1) — same flavor of "main-thread I/O kept causing UI hitches."

Reproducible startup hang: EdgeControl.main() blocks on
PluginWidgetManifest.write() → Data.write(.atomic) → __open syscall
inside the app-group container. App never reaches app.run(), no
window ever appears.

Cause is environmental (sandbox / container-manager state we don't
control) — the .write() syscall just never completes for some users.
Even with no plugin desktop widgets installed, the empty-manifest
write happens on every launch and was the gating call.

Fix:
- Move the entire write dance (mkdir + freshness check + atomic write)
  onto DispatchQueue.global(qos: .utility). Fire-and-forget. Main
  thread proceeds to app.run() instantly.
- Skip the write entirely if the on-disk file already matches the new
  content (avoids a no-op write on every launch).

The widget extension polls plugins.json, so a one-tick stale manifest
is fine. Plugin renderer also self-corrects on first periodic refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <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