Skip to content

fix(update-notifier): retry missed notices and notify daily - #10104

Open
nkolev92 wants to merge 5 commits into
latestfrom
nkolev92/update-notifier-sentinel-on-shown
Open

nkolev92 wants to merge 5 commits into
latestfrom
nkolev92/update-notifier-sentinel-on-shown

Conversation

@nkolev92

@nkolev92 nkolev92 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Avoid consuming the update-notifier throttle when a command exits before its notification is ready. updateCheck() returns { message, onShown }, deferring the sentinel write until the notification is handled at exit.

Behavior

  • Exit order: log notice -> flush streams -> record sentinel -> process.exit(). Late results arriving during the flush are not recorded.
  • Silent mode is an explicit opt-out: hide the notice but still consume the throttle.
  • Failed stderr flushing leaves the sentinel untouched and preserves the existing exit code.
  • Sentinel writes are synchronous and best-effort; failures are logged at verbose level.
  • Increase stable notification frequency from weekly to daily; prereleases remain daily.

Checks without a handled notice retry on every eligible run, even when no update is available, potentially increasing registry traffic.

Progress on internal issue 15901

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.

🟡 Changes recommended

The exit handler can discard a notice queued on stderr under backpressure while still marking it shown, suppressing further notifications for a day.

1 open issue
What changed in this PR

This PR changes npm’s update notifier to record when a notice is displayed rather than when a check starts, allowing later commands to retry notifications that were not shown.

Changes:

  • Return notifications as { message, onShown } and write the sentinel through the callback.
  • Use a daily interval for both stable and prerelease versions, without recording silent notifications.
  • Update tests for notification handoff, display callbacks, and sentinel timing.
File Description
test/​lib/​cli/​update-notifier.js Tests deferred sentinel writes and daily check intervals.
test/​lib/​cli/​exit-handler.js Tests displayed, silent, and failing notification callbacks.
test/​lib/​cli/​entry.js Tests notification-object handoff to npm.
lib/​cli/​update-notifier.js Returns a display callback and adopts daily checks.
lib/​cli/​exit-handler.js Calls the notification callback after logging, except in silent mode.
lib/​cli/​entry.js Stores the returned notification object.

Review effort: Balanced

Comment thread lib/cli/exit-handler.js Resolved
nkolev92 and others added 2 commits October 29, 2026 17:25
Previously the `_update-notifier-last-checked` sentinel was written as
soon as a check *started*, regardless of whether a notice was ever
shown to the user. This meant fast commands (e.g. `npm version`) would
silently consume the check window without the user ever seeing the
update notice, since the sentinel's mtime only ever meant "a check was
attempted", not "a notice was shown".

This redefines the sentinel's mtime to mean "last time a notice was
actually displayed":

- `updateCheck()` now returns `{ message, onShown }` instead of a bare
  message string. The sentinel is written lazily via `onShown()`,
  invoked from the exit handler synchronously (via `writeFileSync`,
  required because `process.on('exit', ...)` can't await async work)
  only after the notice has actually been logged.
- The weekly/daily split between GA and prerelease checks is removed
  in favor of a single daily check for both, since the throttle is now
  tied to actual visibility rather than check attempts.
- `npm.updateNotification` is now a single bundled object
  (`{ message, onShown }`) instead of a bare string, removing the need
  for a separate `updateNotificationShown` field and the duplication
  that came with keeping two npm instance fields in sync.
- When silenced (`npm.silent`), the notice is not shown and the
  sentinel is not written, so a later non-silent run will still get a
  chance to show (and record) the notice.
- Node.js engine compatibility continues to be evaluated fresh on
  every run (never cached), since the active Node version can change
  between invocations (e.g. via nvm).

Ref: github/npm#15901 (comment)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…r path

Full-suite coverage caught two branches the initial tests missed:
- entry.js: the branch that actually assigns npm.updateNotification
  when the notifier resolves a real notification (previously only
  exercised the null/no-op path since update-notifier.js isn't mocked
  in entry.js's own tests).
- exit-handler.js: the try/catch around onShown() when it throws,
  which only logs a verbose message and must not crash the exit path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nkolev92
nkolev92 force-pushed the nkolev92/update-notifier-sentinel-on-shown branch from b20ceee to 3c4b299 Compare October 30, 2026 00:25
…rocess.exit() to ensure the message is shown more consistently.

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.

🟡 Changes recommended

The exit handler can mark an update notice as shown despite a failed stderr flush or Display suppressing output, incorrectly throttling subsequent notices for a day.

2 open issues
1 resolved since last review

Review effort: Balanced

Comment thread lib/cli/exit-handler.js Resolved
Comment thread lib/cli/exit-handler.js Resolved
Record eligible notifications in silent mode and skip recording when stderr flushing fails. Preserve the existing exit code and cover both paths with regression tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b7af3fb9-3cc3-40e6-9d7f-dbb8eee631cd
@nkolev92 nkolev92 changed the title fix(update-notifier): only mark sentinel checked when notice is shown fix(update-notifier): retry missed notices and notify daily Oct 30, 2026
@nkolev92
nkolev92 requested a balanced review from Copilot October 30, 2026 17:07

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.

🟢 Approval recommended

No active review issues were identified for the update-notifier delivery and daily-throttling changes.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@nkolev92
nkolev92 requested a max review from Copilot October 30, 2026 20:38
@nkolev92
nkolev92 marked this pull request as ready for review October 30, 2026 20:42
@nkolev92
nkolev92 requested a review from a team as a code owner October 30, 2026 20:42

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.

🟡 Changes recommended

Paused logging can cause an unseen notice to be marked as shown, and sentinel-write failure diagnostics can be dropped because stderr is not flushed again before exit.

2 open issues

Review effort: Max

Comment thread lib/cli/exit-handler.js Resolved
Comment thread lib/cli/exit-handler.js Resolved
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5f9e5ec7-eea1-4067-8157-b9368a874338
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.

3 participants