Skip to content

fix: Remove unnecessary finalizer from ModuleOutputWriter#1727

Merged
thomhurst merged 1 commit into
mainfrom
fix/1533-dispose-pattern
Jan 1, 2026
Merged

fix: Remove unnecessary finalizer from ModuleOutputWriter#1727
thomhurst merged 1 commit into
mainfrom
fix/1533-dispose-pattern

Conversation

@thomhurst
Copy link
Copy Markdown
Owner

Summary

  • Removes the finalizer since the class only manages managed resources (IServiceScope)
  • Fixes a bug where _scope was not disposed when the buffer had no events
  • Removes GC.SuppressFinalize call since no finalizer exists

Why the finalizer was problematic

  1. Unsafe: The finalizer called Dispose() which accessed managed objects that may already be finalized
  2. Locking in finalizer: Taking locks in finalizers is risky and can cause hangs
  3. Unnecessary: The class only manages managed resources, so a finalizer adds no value

Fixes #1533

Test plan

  • Existing unit tests pass
  • Module output displays correctly

🤖 Generated with Claude Code

- Remove finalizer since class only manages managed resources
- Fix bug where _scope was not disposed when buffer had no events
- Remove GC.SuppressFinalize since no finalizer exists
- Add documentation explaining why finalizer is not needed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings January 1, 2026 17:48
@thomhurst
Copy link
Copy Markdown
Owner Author

Summary

Removes unsafe finalizer from ModuleOutputWriter and fixes resource leak where IServiceScope wasn't disposed in early return path.

Critical Issues

None found ✅

Suggestions

None - the changes are correct and well-documented.

Analysis

The PR correctly addresses the finalizer issues:

  1. Finalizer removal is appropriate: The class only manages IServiceScope (a managed resource), so a finalizer adds no value and is actually harmful:

    • Accessing managed objects from finalizers is unsafe (they may already be finalized)
    • Taking locks in finalizers can cause deadlocks
  2. Resource leak fix: The early return path at line 136 now properly disposes the scope, preventing a leak when the buffer has no events.

  3. Dispose pattern: The two _scope.Dispose() calls (lines 136 and 180) are in mutually exclusive code paths, so the scope is correctly disposed exactly once in all scenarios.

  4. Documentation: The added XML remarks clearly explain the design decision.

Verdict

APPROVE - No critical issues

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR removes the problematic finalizer from ModuleOutputWriter and fixes a resource leak where the IServiceScope was not disposed when the buffer had no events.

Key changes:

  • Removed the finalizer that unsafely called Dispose()
  • Fixed bug where _scope.Dispose() was not called in the early return path when buffer has no events
  • Removed unnecessary GC.SuppressFinalize(this) call since no finalizer exists

@thomhurst thomhurst merged commit 1f44eb7 into main Jan 1, 2026
17 of 18 checks passed
@thomhurst thomhurst deleted the fix/1533-dispose-pattern branch January 1, 2026 18:03
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.

Code smell: ModuleOutputWriter has both Dispose and Finalizer with same code

2 participants