Skip to content

fix: sync-over-async, lazy enumeration, specific catches (CQ-004, CQ-010, CQ-011)#372

Merged
laurentiu021 merged 1 commit into
mainfrom
fix/medium-code-quality
May 15, 2026
Merged

fix: sync-over-async, lazy enumeration, specific catches (CQ-004, CQ-010, CQ-011)#372
laurentiu021 merged 1 commit into
mainfrom
fix/medium-code-quality

Conversation

@laurentiu021

@laurentiu021 laurentiu021 commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Addresses 3 MEDIUM findings from QA audit.

Changes

CQ-004: ProcessManagerViewModel (MEDIUM — thread safety)

  • Replaced sync-over-async GetAwaiter().GetResult() with proper await inside Task.Run async lambda
  • Prevents thread pool thread blocking during process snapshot

CQ-010: DeepCleanupService (MEDIUM — performance)

  • Replaced Directory.GetFiles()/GetDirectories() with lazy Directory.EnumerateFiles()/EnumerateDirectories()
  • Reduces memory pressure on directories with millions of files (user temp)

CQ-011: TracerouteService (MEDIUM — error handling)

  • Bare catch {} replaced with specific PingException, SocketException, InvalidOperationException
  • Subscriber error catch narrowed from bare catch to catch (Exception)

Housekeeping

  • Added audit JSON files to .gitignore

Build

  • 0 errors, 0 new warnings

Summary by CodeRabbit

Bug Fixes

  • Resolved async operation blocking in the process manager
  • Reduced memory consumption during cleanup operations
  • Improved error handling in the network diagnostics tool

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR addresses three quality issues across core system services: removing sync-over-async blocking in process enrichment, switching to lazy enumeration for memory efficiency in cleanup operations, and narrowing exception handling in network diagnostics.

Changes

Quality Fixes v0.48.11

Layer / File(s) Summary
ProcessManagerViewModel async/await correction
SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs
RefreshAsync now properly awaits _service.SnapshotAsync() inside an async Task.Run delegate instead of blocking synchronously with GetAwaiter().GetResult().
DeepCleanupService lazy enumeration
SysManager/SysManager/Services/DeepCleanupService.cs
EnumerateFiles and EnumerateDirectoriesDepthFirst switch from eager Directory.GetFiles/GetDirectories to lazy Directory.EnumerateFiles/EnumerateDirectories, skipping inaccessible directories on IO or permission exceptions instead of failing or returning empty collections.
TracerouteService exception handling refinement
SysManager/SysManager/Services/TracerouteService.cs
RunAsync replaces blanket per-probe exception handling with explicit catches for PingException, SocketException, and InvalidOperationException; RaiseHopCompleted narrows subscriber error handling from untyped catch to explicit catch (Exception).
Release notes documentation
CHANGELOG.md
Adds v0.48.11 release entry (2026-05-15) documenting the three fixes with tracking IDs CQ-004, CQ-010, and CQ-011.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • laurentiu021/SystemManager#298: Both modify ProcessManagerViewModel.RefreshAsync by offloading enrichment work to background Task.Run execution.
  • laurentiu021/SystemManager#357: Both refine exception handling by replacing broad catch patterns with specific exception types in traceroute-related services.

Poem

🐰 Three little fixes hop into place,
Sync-over-async removed from the race,
Lazy enums now tread light and swift,
Exception handlers pinpoint each drift,
v0.48.11 hops forth with a gift! 🌱

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main fixes in the changeset (sync-over-async, lazy enumeration, specific exception handling) with direct reference to the code quality issue identifiers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/medium-code-quality

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@SysManager/SysManager/Services/DeepCleanupService.cs`:
- Around line 381-384: The EnumerateFiles/EnumerateDirectories usage currently
only catches exceptions thrown when creating the IEnumerable but not those
thrown during deferred iteration; move each foreach into its own try/catch so
iteration is protected: for the files loop (in DeepCleanupService) wrap "foreach
(var f in files) yield return f;" inside a try that catches IOException and
UnauthorizedAccessException and continues on exception, and for the dirs loop
wrap "foreach (var d in dirs) stack.Push(d);" inside a try that on
IOException/UnauthorizedAccessException sets dirs to empty or simply continues;
update the blocks around the variables `files`, `dirs`, and the stack push to
ensure iteration exceptions are handled the same way as enumeration
construction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6eafaac3-e1a6-4b8d-bc4d-7545c581e734

📥 Commits

Reviewing files that changed from the base of the PR and between 8321bf3 and 031f899.

📒 Files selected for processing (5)
  • .gitignore
  • CHANGELOG.md
  • SysManager/SysManager/Services/DeepCleanupService.cs
  • SysManager/SysManager/Services/TracerouteService.cs
  • SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Build & unit tests
🔇 Additional comments (3)
CHANGELOG.md (1)

9-20: LGTM!

SysManager/SysManager/ViewModels/ProcessManagerViewModel.cs (1)

57-59: LGTM!

SysManager/SysManager/Services/TracerouteService.cs (1)

57-59: LGTM!

Also applies to: 106-106

Comment on lines +381 to 384
try { files = Directory.EnumerateFiles(cur); } catch (IOException) { continue; } catch (UnauthorizedAccessException) { continue; }
try { dirs = Directory.EnumerateDirectories(cur); } catch (IOException) { dirs = []; } catch (UnauthorizedAccessException) { dirs = []; }
foreach (var f in files) yield return f;
foreach (var d in dirs) stack.Push(d);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In .NET, can Directory.EnumerateFiles/Directory.EnumerateDirectories throw IOException or UnauthorizedAccessException during foreach iteration (MoveNext), not just when the enumerable is created?

💡 Result:

Yes, in.NET, Directory.EnumerateFiles and Directory.EnumerateDirectories can throw exceptions such as UnauthorizedAccessException and IOException during the foreach iteration (specifically when MoveNext is called), not just when the enumerable is initially created [1][2]. Because these methods use deferred execution—acting as wrappers around native file system enumeration APIs—they do not retrieve the entire list of files or directories upfront [3][4]. Instead, they fetch entries incrementally as you iterate [1][2]. Consequently, if the enumerator encounters a directory it cannot access, a file that has been locked, or other I/O-related issues while traversing the file system, the exception will be raised at the point of iteration [1][2]. To handle these scenarios robustly, you can use the EnumerationOptions class (available in modern.NET versions) to configure the behavior of the enumerator [5][6]. Specifically, setting the IgnoreInaccessible property to true allows the enumerator to skip files or directories that would otherwise trigger an UnauthorizedAccessException, enabling the iteration to continue [5][6]. For older versions of.NET or more complex error handling, you may need to implement custom logic to wrap the enumeration in a way that catches and handles these exceptions during the MoveNext process [7][1].

Citations:


🏁 Script executed:

find . -name "DeepCleanupService.cs" -type f

Repository: laurentiu021/SystemManager

Length of output: 125


🏁 Script executed:

sed -n '370,410p' ./SysManager/SysManager/Services/DeepCleanupService.cs | cat -n

Repository: laurentiu021/SystemManager

Length of output: 1961


Handle deferred Enumerate* exceptions inside iteration.

Directory.EnumerateFiles and Directory.EnumerateDirectories use deferred execution and can throw IOException or UnauthorizedAccessException during foreach iteration (via MoveNext), not just when the enumerable is created. The current exception handling only wraps the enumerable creation, leaving iteration unprotected.

Move the foreach loops inside the try blocks:

Proposed fix for EnumerateFiles
-            IEnumerable<string> files;
-            IEnumerable<string> dirs;
-            try { files = Directory.EnumerateFiles(cur); } catch (IOException) { continue; } catch (UnauthorizedAccessException) { continue; }
-            try { dirs = Directory.EnumerateDirectories(cur); } catch (IOException) { dirs = []; } catch (UnauthorizedAccessException) { dirs = []; }
-            foreach (var f in files) yield return f;
-            foreach (var d in dirs) stack.Push(d);
+            IEnumerable<string> dirs = [];
+            try
+            {
+                foreach (var f in Directory.EnumerateFiles(cur))
+                    yield return f;
+            }
+            catch (IOException) { continue; }
+            catch (UnauthorizedAccessException) { continue; }
+
+            try { dirs = Directory.EnumerateDirectories(cur); }
+            catch (IOException) { dirs = []; }
+            catch (UnauthorizedAccessException) { dirs = []; }
+
+            foreach (var d in dirs) stack.Push(d);
Proposed fix for EnumerateDirectoriesDepthFirst
-            IEnumerable<string> dirs;
-            try { dirs = Directory.EnumerateDirectories(cur); } catch (IOException) { continue; } catch (UnauthorizedAccessException) { continue; }
-            foreach (var d in dirs) stack.Push(d);
+            try
+            {
+                foreach (var d in Directory.EnumerateDirectories(cur))
+                    stack.Push(d);
+            }
+            catch (IOException) { continue; }
+            catch (UnauthorizedAccessException) { continue; }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SysManager/SysManager/Services/DeepCleanupService.cs` around lines 381 - 384,
The EnumerateFiles/EnumerateDirectories usage currently only catches exceptions
thrown when creating the IEnumerable but not those thrown during deferred
iteration; move each foreach into its own try/catch so iteration is protected:
for the files loop (in DeepCleanupService) wrap "foreach (var f in files) yield
return f;" inside a try that catches IOException and UnauthorizedAccessException
and continues on exception, and for the dirs loop wrap "foreach (var d in dirs)
stack.Push(d);" inside a try that on IOException/UnauthorizedAccessException
sets dirs to empty or simply continues; update the blocks around the variables
`files`, `dirs`, and the stack push to ensure iteration exceptions are handled
the same way as enumeration construction.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 55.55556% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ysManager/SysManager/Services/TracerouteService.cs 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

{
try { ((Action<TracerouteHop>)h).Invoke(hop); }
catch { /* swallow subscriber errors */ }
catch (Exception) { /* swallow subscriber errors to protect iteration */ }
@laurentiu021
laurentiu021 merged commit 742326d into main May 15, 2026
5 checks passed
@laurentiu021
laurentiu021 deleted the fix/medium-code-quality branch May 15, 2026 07:01
laurentiu021 added a commit that referenced this pull request May 22, 2026
Add CHANGELOG entry for v0.28.14 — CodeQL missed-using-statement fixes.

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
laurentiu021 added a commit that referenced this pull request May 22, 2026
…010, CQ-011) (#372)

Co-authored-by: laurentiu021 <laurentiu021@users.noreply.github.com>
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