fix(calendar): sync Google Calendar on focus, resume, and manual refresh - #297
Merged
Conversation
Users were waiting 5+ min for remote Google Calendar changes (including
deletions) to appear in memry because sync ran only on the background
5-min poll. macOS App Nap and system sleep further delayed this — the
poll interval drifts until the app is foreground.
Adds three faster sync triggers, all funneled through a single 10-second
cooldown so rapid signals don't stampede the API:
- Window focus: mainWindow.on('focus') fires when the user clicks back
into memry.
- System resume: powerMonitor.on('resume') fires when the machine wakes
from sleep, registered with the runner lifecycle so it's cleaned up
on stopGoogleCalendarSyncRunner.
- Manual refresh: new button in the calendar toolbar that calls the
existing refreshGoogleCalendarProvider IPC (REFRESH_PROVIDER was
already wired; only the UI surface was missing).
The 5-min background poll remains unchanged as a safety net.
Tests: 7 new in sync-service-trigger.test.ts covering cooldown behavior,
cooldown expiry, error swallowing, and powerMonitor handler
registration/cleanup. The existing cadence test's electron mock was
extended with powerMonitor since the runner now imports it.
h4yfans
added a commit
that referenced
this pull request
May 6, 2026
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
Users were waiting 5+ min for remote Google Calendar changes (including deletions) to propagate to memry because sync only ran on the background 5-min poll. macOS App Nap / system sleep make this worse —
setIntervaldoesn't catch up on wake.This PR adds three faster sync triggers, all funneled through a single 10-second cooldown so rapid-fire signals don't stampede the API:
mainWindow.on('focus')fires when the user clicks back into memry.powerMonitor.on('resume')fires on wake-from-sleep, registered with the runner lifecycle (cleaned up instopGoogleCalendarSyncRunner).refreshGoogleCalendarProviderIPC.REFRESH_PROVIDERwas already wired end-to-end; only the UI surface was missing. The button is shown only when Google calendars are connected and spins while the sync is in-flight.The 5-min background poll remains unchanged as the silent safety net.
Why
Reported symptom: events deleted in Google Calendar still appeared in memry for 5+ minutes. Investigation confirmed the deletion pipeline itself (
archivedAttombstone + projection filter) is correct — the delay was purely in how often sync ran, compounded by OS-level timer throttling.What changed
apps/desktop/src/main/calendar/google/google-sync-runner.tstriggerGoogleCalendarSyncNow(reason)with 10s cooldown;powerMonitor.on('resume', …)wired to runner start/stop.apps/desktop/src/main/calendar/google/sync-service.tstriggerGoogleCalendarSyncNow.apps/desktop/src/main/calendar/google/sync-service-cadence.test.tspowerMonitorin electron mock (runner now imports it).apps/desktop/src/main/calendar/google/sync-service-trigger.test.tsapps/desktop/src/main/index.tsmainWindow.on('focus', …)fires the window-focus trigger.apps/desktop/src/renderer/src/components/calendar/calendar-shell.tsxReviewer notes
CalendarChannels.invoke.REFRESH_PROVIDER, which was already wired tosyncGoogleCalendarNow().CALENDAR_PUSH_ENABLED=1) is unaffected. When push is enabled, poll already drops to 30 min; these new triggers make the poll-only path feel closer to push without requiring the server-side watch infrastructure.__resetTriggerForTests()helper fromgoogle-sync-runner.tsto keep the cooldown deterministic across test cases.Test plan
pnpm --filter @memry/desktop test— 7130 pass (+7 new), 1 skipped (pre-existing)pnpm --filter @memry/desktop typecheck:node— cleanpnpm --filter @memry/desktop typecheck:web— cleanOut of scope
syncTokenexpires or is invalidated, the fallback initial sync doesn't archive events that existed locally but are no longer returned by Google. Worth a separate PR once this one ships; lower priority because it only bites on re-auth / 30+ day offline windows.