Skip to content

fix(updates): suppress background check errors#2722

Open
janburzinski wants to merge 2 commits into
mainfrom
emdash/update-not-available-after-idle-rrzq4
Open

fix(updates): suppress background check errors#2722
janburzinski wants to merge 2 commits into
mainfrom
emdash/update-not-available-after-idle-rrzq4

Conversation

@janburzinski

Copy link
Copy Markdown
Collaborator

Description

  • suppress user-facing errors from automatic update checks (could be caused when pc is just waking up again)
  • manual update errors are unchanged
Checklist
  • I kept this PR small and focused
  • I ran a self-review before opening this PR
  • I ran the relevant local checks or explained why not
  • I updated docs when behavior or setup changed
  • I added or updated tests when behavior changed, or explained why not
  • I only added comments where the logic is not obvious
  • I used Conventional Commits for commit
    messages and, when possible, the PR title

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a source discriminator ('background' | 'manual') to update checks so that errors from automatic/scheduled checks (e.g., triggered immediately after the PC wakes from sleep with no network) are silently swallowed instead of surfaced to the user, while manually-triggered check errors are unchanged.

  • update-service.ts: Tracks currentCheckSource per in-flight check; on error, if the check is a 'background' check in 'checking' state, the error is suppressed, state is reset to idle, and updateNotAvailableEvent is emitted so the renderer transitions cleanly out of 'checking'.
  • update-store.ts: Removes the now-redundant not-available union member (both update-not-available and the new suppression path converge on idle), and forwards the source argument correctly from all call sites.
  • controller.ts: Adds an optional args.source parameter to the RPC handler, defaulting to 'manual' for backward-compatible callers.

Confidence Score: 5/5

Safe to merge — the suppression path is narrowly scoped to background checks in the 'checking' state, and it correctly emits updateNotAvailableEvent to close the renderer state loop.

All three changed files make targeted, well-reasoned changes. The source tracking is set before the check begins and cleared only after the promise settles, so the error handler always sees a consistent value. Manual check errors and all post-check-phase errors (download, install) are completely unaffected by the new suppression guard.

No files require special attention.

Important Files Changed

Filename Overview
apps/emdash-desktop/src/main/core/updates/update-service.ts Introduces currentCheckSource tracking and background-error suppression; logic is correct — source is set before the check starts and cleared in finally, so the error handler always sees a valid value. The updateNotAvailableEvent emission in the suppression path ensures the renderer exits the checking state cleanly.
apps/emdash-desktop/src/renderer/lib/stores/update-store.ts Removes the not-available union member (both paths now converge on idle) and threads source through all call sites. Behaviorally equivalent for the renderer.
apps/emdash-desktop/src/main/core/updates/controller.ts Adds optional args.source to the RPC handler; defaults to 'manual' for backward-compatible callers without arguments — intentional and correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant R as Renderer (UpdateStore)
    participant C as Controller (RPC)
    participant S as UpdateService
    participant AU as electron-updater

    Note over R,AU: Background scheduled check (e.g., after wakeup)
    R->>C: "rpc.update.check({ source: 'background' })"
    C->>S: checkForUpdates('background')
    S->>S: "currentCheckSource = 'background'"
    S->>AU: checkForUpdatesAndNotify()
    AU-->>R: "updateCheckingEvent → state = 'checking'"

    alt Network unavailable (background)
        AU->>S: emit('error', err)
        S->>S: "status='checking' && source='background' → suppress"
        S->>S: "updateState.status = 'idle'"
        S-->>R: "updateNotAvailableEvent → state = 'idle'"
        Note over S: log.warn only, no user-facing error
    else Network unavailable (manual)
        AU->>S: emit('error', err)
        S->>S: "source='manual' → do NOT suppress"
        S-->>R: "updateErrorEvent → state = 'error'"
    else Update available
        AU->>S: emit('update-available', info)
        S-->>R: "updateAvailableEvent → state = 'available'"
    else No update
        AU->>S: emit('update-not-available')
        S-->>R: "updateNotAvailableEvent → state = 'idle'"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant R as Renderer (UpdateStore)
    participant C as Controller (RPC)
    participant S as UpdateService
    participant AU as electron-updater

    Note over R,AU: Background scheduled check (e.g., after wakeup)
    R->>C: "rpc.update.check({ source: 'background' })"
    C->>S: checkForUpdates('background')
    S->>S: "currentCheckSource = 'background'"
    S->>AU: checkForUpdatesAndNotify()
    AU-->>R: "updateCheckingEvent → state = 'checking'"

    alt Network unavailable (background)
        AU->>S: emit('error', err)
        S->>S: "status='checking' && source='background' → suppress"
        S->>S: "updateState.status = 'idle'"
        S-->>R: "updateNotAvailableEvent → state = 'idle'"
        Note over S: log.warn only, no user-facing error
    else Network unavailable (manual)
        AU->>S: emit('error', err)
        S->>S: "source='manual' → do NOT suppress"
        S-->>R: "updateErrorEvent → state = 'error'"
    else Update available
        AU->>S: emit('update-available', info)
        S-->>R: "updateAvailableEvent → state = 'available'"
    else No update
        AU->>S: emit('update-not-available')
        S-->>R: "updateNotAvailableEvent → state = 'idle'"
    end
Loading

Reviews (2): Last reviewed commit: "fix(updates): reset renderer after suppr..." | Re-trigger Greptile

Comment thread apps/emdash-desktop/src/main/core/updates/update-service.ts
@janburzinski

Copy link
Copy Markdown
Collaborator Author

@greptileai

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