Fix directory enumeration hang - #1860
Conversation
Handle directories that disappear during scanning and propagate unexpected enumeration failures instead of leaving observers waiting indefinitely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
The recursive enumeration observable can call IObserver.OnNext concurrently from multiple ActionBlock workers, which violates Rx observer thread-safety expectations and can cause race-condition failures.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes a potential hang in the FastDirectoryWalkerFactory directory enumeration pipeline when the filesystem changes during a scan (e.g., a directory is deleted between discovery and recursive enumeration). It makes DirectoryNotFoundException during recursive enumeration recoverable and ensures unexpected enumeration failures are logged and propagated via OnError, allowing scans to fail fast instead of stalling subscribers indefinitely.
Changes:
- Catch and suppress
DirectoryNotFoundExceptionduring recursive enumeration to handle directory-deletion races. - Forward enumeration errors to observers (and log them) so the replayed observable terminates instead of hanging.
- Add regression tests covering the “directory disappears” race and unexpected enumeration failure propagation/logging.
File summaries
| File | Description |
|---|---|
src/Microsoft.ComponentDetection.Common/FastDirectoryWalkerFactory.cs |
Adds recoverable handling for DirectoryNotFoundException during recursive enumeration and forwards unexpected errors via OnError with logging. |
test/Microsoft.ComponentDetection.Common.Tests/FastDirectoryWalkerFactoryTests.cs |
Adds regression tests verifying completion on disappearing directories and error propagation/logging for unexpected enumeration failures. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
👋 Hi! It looks like you modified some files in the
If none of the above scenarios apply, feel free to ignore this comment 🙂 |
Summary
Fix a directory enumeration failure that can leave Component Detection waiting indefinitely when the source tree changes during a scan.
Problem
Component Detection first discovers directories and then enumerates them concurrently. In a mutable build tree, a discovered directory can be deleted before recursive enumeration begins. The resulting
DirectoryNotFoundExceptionfaults the directory enumerationActionBlock.Errors from the concatenated enumeration observables were also not forwarded to the outer observer. As a result, an unexpected enumeration failure could leave the shared replay observable without a terminal notification. Detectors waiting for enumeration to complete would then remain blocked indefinitely.
This behavior was observed in a process dump where:
DirectoryNotFoundException.Solution
DirectoryNotFoundExceptionduring recursive enumeration as a recoverable race and continue scanning the remaining directories.OnErrorso the scan fails instead of hanging.Other I/O and enumeration exceptions are not suppressed.
Tests
Added regression coverage that verifies: