Conversation
👷 Deploy request for nx-docs pending review.Visit the deploys page to approve it
|
👷 Deploy request for nx-dev pending review.Visit the deploys page to approve it
|
Member
|
Thanks for the PR. Approving the workflow run so CI can actually build it, and assigning it for review.
|
Contributor
|
View your CI Pipeline Execution ↗ for commit 29cf282
☁️ Nx Cloud last updated this comment at |
The daemon's outdated check ran on a 20 ms interval. Every tick read the process file, resolved the installed nx version and hashed every lockfile at the workspace root. With a 1.7 MB yarn.lock an idle daemon read the file 34 to 50 times a second: 8 to 12% of a core and 57 MB/s on a Windows laptop, 5 to 6% of a core on an M4 Mac, for a daemon doing nothing. The watch already names every changed path. The lockfile hash is now recorded once, before the watch starts, and compared only when a batch names a lockfile at the root; a change the kernel dropped arrives as an ordinary batch after the re-walk. The process-file check already ran on the watch event for that file, and now also runs when the watch reports dropped events, since that event may have been among them. A client connection runs all three checks once before the daemon serves it, so a change the watch never reported is still caught at the next request. The interval is gone.
sdjayna
force-pushed
the
sj/daemon-outdated-check-events
branch
from
September 21, 2026 20:24
29cf282 to
b435eb5
Compare
This branch has not been deployed
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.
The daemon's outdated check moves from a 20 ms
setIntervalonto the workspace watch and the client connection, and the interval goes. An idle daemon stops re-reading and hashing the lockfiles 34 to 50 times a second; restart behaviour is unchanged.Workspace: 1,188 projects,
yarn.lock1.69 MB. A lockfile rewrite on the patched daemon loggedlock file hash changed,LOCK_FILES_CHANGED,Restarting daemon...within a second of the write; an unrelated write logged nothing.Current Behavior
server.tsstarts asetInterval(..., 20)after writing the process file. Every tick:getDaemonProcessIdSync()(read ofserver-process.json),isNxVersionMismatch()(resolve and read the installednx/package.json), thenlockFileHashChanged(): fiveexistsSync,hashFile()of each lockfile present,hashArray. With a 1.69 MByarn.lockthat is 2.34 GB read in 41 s on an idle Windows laptop, every open passing through the filter drivers. On a corporate image with three of them, about 505 µs per create between them, the loop costs about 140 ms of filter-driver time per second of idle before the daemon's own CPU.Expected Behavior
recordLockFileHash()runs once instartServer, before the watch is set up, so any change the watch reports is a real change.routeAppliedChangesinproject-graph-incremental-recomputation.ts, which already receives every applied batch and already callsrestartDaemonIfIgnoreFilesChanged, now callsrestartDaemonIfLockFilesChanged(paths)beside it. Only a batch namingpackage-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockborbun.lockat the root reads the lockfiles. A restart goes throughhandleServerProcessTerminationWithRestartwith the same log lines.stopDaemonIfReplaced(event-driven since feat(core): add includeIgnored filesets and let the workspace context own the daemon's watch #37025) now also runs on the rescan marker.stopDaemonIfOutdated()runs once per client connection: process file, installed version, lockfile hash. It returns early and the shutdown destroys the new socket with the others; the client reconnects to whichever daemon comes next, as today when the interval fired mid-request. This is the safety net for a change the watch never reported.daemonIsOutdated(),lockFileHashChanged()andexistingLockHashare removed fromserver.ts. No timer replaces them.Implementation Notes
restart-checks.ts(+120),restart-checks.spec.ts(+152),server.ts(-91),project-graph-incremental-recomputation.ts(+9).restart-checks.spec.ts: 14 pass, including: a root lockfile change restarts withLOCK_FILES_CHANGED; paths that do not name a root lockfile (includingpkg/yarn.lock) read nothing; an unchanged rewrite reads once and does not restart;stopDaemonIfOutdatedfor nothing changed, lockfile changed unreported, another process owning the process file, installed version differing;stopDaemonIfReplacedon rescan with and without ownership.vitest run src/daemon: 19 files, 282 passed.tsc --noEmitand eslint clean on the four files.Related Issue(s)
Fixes #37112
#37025 made the process-file check event-driven; this removes the poll that ran beside it. #37086 and #37088 concern what a rescan can hide from the outputs tracker; this change relies on the watch's re-walk already on master, not on those PRs.