mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
* feat(desktop): observe abnormal exits (runtime 闪退) + child-process crashes The crash telemetry only covered renderer crashes (desktop_renderer_crash) and startup failures (packaged_runtime_failed). The most common "闪退" a user reports — the app was running fine, then the whole window vanished — is a MAIN-process crash / OS kill / force-quit after a hang, and none of it reaches analytics: a dead process can't report itself, and uncaughtException/unresponsive were log-only. Add abnormal-exit detection via a session marker: beginDesktopSession stamps a `clean: false` marker at launch; a graceful shutdown flips it clean. If the next launch finds the previous marker still dirty, the previous run died without a graceful quit — emit `desktop_unclean_exit` (previous version/session/started-at) once the daemon is up to relay it. This catches the whole class regardless of cause. Also emit `desktop_child_process_crash` on `child-process-gone` (GPU / utility crashes — a common cause of a window that then goes blank). Both events ride the existing free-form POST /api/observability/event (no contract change), same as desktop_renderer_crash. The lifecycle logic is a pure, unit-tested module; all fs/telemetry is best-effort and can never block startup or shutdown. * fix(desktop): only report unclean exit for runs that reached running Review (nettee): stamping the dirty marker at startup meant a bootstrap failure AFTER beginDesktopSession but before the app was up would leave the marker dirty and be reported as desktop_unclean_exit next launch — but that's a startup failure (already covered by packaged_runtime_failed), not a 'while running' crash. Add a reachedRunning flag: the marker is written not-yet-running at startup, markDesktopSessionRunning flips it true only once the runtime is up (after onDesktopReady), and a previous run is reported ONLY when it reached running and never went clean. This also makes each previous state reported at most once (begin overwrites the marker). * fix(desktop): mark session clean at end of shutdown, not start Review (nettee): endDesktopSessionCleanly ran at the very start of shutdown(), before the awaited teardown (beforeShutdown / IPC close / desktop.close / app.quit). A quit that then hangs in one of those steps and is force-quit or OS-killed would already have flipped the marker clean, hiding that abnormal exit. Move the clean-mark to just before app.quit(), after teardown completes. * fix(desktop): mark session running on actual reveal, not runtime creation Review (nettee): createDesktopRuntime() starts async bootstrap with void tick() and returns before the first window load/reveal, so calling markDesktopSessionRunning right after it fired too early — a crash during the first load would be mislabeled a runtime exit. Add an onRevealed callback fired from revealMainWindow (the real 'app is up' moment: web app mounted + window shown) and mark running from there instead. * fix(desktop): persist unclean-exit until its report is acked Review (nettee): beginDesktopSession overwrote the marker (dropping the crash from disk) while the crash was only held in memory and reported via a fire-and-forget POST that swallows failures — so a report that fails (daemon not reachable yet, transient network) lost the signal permanently. Carry the crash forward in the marker's unreportedCrash field; report returns whether it was acked; clearReportedCrash removes it only on success, so a failed report retries next launch. markRunning / clean preserve the carried-forward crash. * fix(desktop): queue unreported crashes so consecutive failures lose none Review (nettee): with a single carried-forward slot, a launch that is only retrying crash A and then itself crashes replaced A with B on the next launch, losing A. Carry a bounded queue (unreportedCrashes[], cap 20, oldest dropped) instead: begin appends the previous run's crash to the carried list, each is reported and cleared independently by sessionId, so a consecutive crash+failed- report sequence keeps every crash. markRunning/clean preserve the queue.