fix(updater): stop embeddings utility process on quit (#805) - #820
Merged
Conversation
The before-quit shutdown chain stopped the capture server, voice model, image processing, sync runtime and vault, but never terminated the embeddings utilityProcess. That worker only self-exits after a 30s idle timer, and on Windows utilityProcess.fork runs as the app binary (Memrynote.exe). At "Restart to install" the phantom Memrynote.exe could outlive the NSIS CHECK_APP_RUNNING retry window, so the installer refused the update with "MemryNote cannot be closed" — the user had to uninstall to update. Await stopEmbeddingModel() right after stopImageProcessing() so every utilityProcess child dies before performQuitAndInstall() hands off to the installer. stopEmbeddingModel already existed (idempotent, force-kills a wedged worker after 3s) but had no production caller. Add a regression test asserting the embeddings worker is stopped during graceful before-quit cleanup.
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
There was a problem hiding this comment.
Pull request overview
Ensures the embeddings Electron utilityProcess is explicitly terminated during the before-quit graceful shutdown path, preventing lingering Memrynote.exe processes on Windows that can block NSIS in-app update installs.
Changes:
- Wire
stopEmbeddingModel()into thebefore-quitshutdown chain immediately afterstopImageProcessing(). - Add a regression test asserting the embeddings worker stop hook is called during graceful shutdown.
- Adjust async-flush timing in the phase2 main-process test to accommodate the extended shutdown chain.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| apps/desktop/src/main/index.ts | Adds stopEmbeddingModel() to the graceful shutdown sequence so the embeddings utilityProcess is terminated before quit/update-install handoff. |
| apps/desktop/src/main/index.phase2.test.ts | Mocks/spies stopEmbeddingModel() and asserts it’s invoked during before-quit cleanup; updates microtask flushing loop. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
1615
to
1617
| for (let i = 0; i < 40; i++) { | ||
| await Promise.resolve() | ||
| } |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Address PR review: the before-quit reject-path test drained the shutdown promise chain by looping a hard-coded number of microtask ticks, coupling the assertion to the chain length (adding the embeddings stop step had required bumping 30->40). Replace it with a bounded flushUntil() helper that drains microtasks until app.exit has been called, so the test no longer breaks when async shutdown steps are added or removed.
Comment on lines
+418
to
+422
| async function flushUntil(predicate: () => boolean, maxTicks = 100): Promise<void> { | ||
| for (let i = 0; i < maxTicks && !predicate(); i++) { | ||
| await Promise.resolve() | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #805 — Windows in-app updates refused to install with "MemryNote cannot be closed," even when no window was open (reported on Win10 v2026.718.3; part of #795).
The
before-quitshutdown chain (apps/desktop/src/main/index.ts) stopped the capture server, voice model, image processing, sync runtime and vault — but never terminated the embeddingsutilityProcess. That worker only self-exits after a 30s idle timer, and on WindowsutilityProcess.forkruns as the app binary (Memrynote.exe). At "Restart to install," the lingeringMemrynote.execould outlive the NSISCHECK_APP_RUNNINGretry window, so the installer refused the update and the user had to uninstall to update.The fix awaits
stopEmbeddingModel()immediately afterstopImageProcessing(), so everyutilityProcesschild is stopped beforeperformQuitAndInstall()hands off to the installer.stopEmbeddingModel()already existed (idempotent, graceful shutdown message + 3s force-kill fallback) — it simply had no production caller. This mirrors the already-wiredstopVoiceModel/stopImageProcessingsteps exactly.Scope is the primary fix only. The issue also floated a defensive Windows process-kill guard mirroring the darwin
updater-install-guard, but that guard is currently dormant —writePendingInstallMarker()has zero production callers, so it never fires even on macOS. Mirroring dead code would add risk without benefit; noted for a possible separate follow-up.Release note
none
Test plan
pnpm --filter @memry/desktop test:main— full main suite green (3993 passed, 1 skipped), including a new regression test asserting the embeddings worker is stopped during gracefulbefore-quitcleanup (added toindex.phase2.test.ts).pnpm --filter @memry/desktop typecheck:node— clean.eslintonindex.ts— clean.git diff --check— clean.Memrynote.exelingers in Task Manager after quit) needs a packaged Windows build — please confirm via CI or a manual Windows smoke.