Skip to content

fix(updater): stop embeddings utility process on quit (#805) - #820

Merged
h4yfans merged 2 commits into
mainfrom
windows-update-stop-embeddings-on-quit
Jul 22, 2026
Merged

fix(updater): stop embeddings utility process on quit (#805)#820
h4yfans merged 2 commits into
mainfrom
windows-update-stop-embeddings-on-quit

Conversation

@h4yfans

@h4yfans h4yfans commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

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-quit shutdown chain (apps/desktop/src/main/index.ts) 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 lingering Memrynote.exe could outlive the NSIS CHECK_APP_RUNNING retry window, so the installer refused the update and the user had to uninstall to update.

The fix awaits stopEmbeddingModel() immediately after stopImageProcessing(), so every utilityProcess child is stopped before performQuitAndInstall() 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-wired stopVoiceModel / stopImageProcessing steps 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 graceful before-quit cleanup (added to index.phase2.test.ts).
  • The regression test was verified red before the wiring and green after (TDD).
  • pnpm --filter @memry/desktop typecheck:node — clean.
  • eslint on index.ts — clean. git diff --check — clean.
  • Not verifiable on macOS: the end-to-end Windows installer path (update installs without the "cannot be closed" prompt; no Memrynote.exe lingers in Task Manager after quit) needs a packaged Windows build — please confirm via CI or a manual Windows smoke.

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.
Copilot AI review requested due to automatic review settings July 21, 2026 22:53
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
memry-docs Ignored Ignored Preview Jul 22, 2026 12:12am
memrynote-landing Ignored Ignored Preview Jul 22, 2026 12:12am

@github-actions github-actions Bot added bug Something isn't working test labels Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

React Doctor found no new issues. 🎉

Reviewed by React Doctor for commit a06f6d8.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 the before-quit shutdown chain immediately after stopImageProcessing().
  • 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

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

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.
Copilot AI review requested due to automatic review settings July 22, 2026 00:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

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()
}
}
@h4yfans
h4yfans marked this pull request as ready for review July 22, 2026 00:27
@h4yfans
h4yfans merged commit 582db0c into main Jul 22, 2026
20 of 21 checks passed
@h4yfans
h4yfans deleted the windows-update-stop-embeddings-on-quit branch July 22, 2026 00:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Windows update refuses to install ("MemryNote cannot be closed") — embeddings utility process not terminated on quit

2 participants