Skip to content

Conversation

Aaronontheweb
Copy link
Member

@Aaronontheweb Aaronontheweb commented Sep 2, 2025

Changes

  • Detect when running in IIS/Windows Service environments where Console.Out and Console.Error are redirected to the same StreamWriter.Null singleton
  • Skip console output entirely in these environments to prevent race conditions that cause IndexOutOfRangeException and cascade failures
  • Improve DefaultLogger error handling to prevent feedback loops
  • Add unit tests for non-console scenarios

The race condition occurs because:

  1. IIS/Services redirect both Console.Out and Console.Error to StreamWriter.Null
  2. StreamWriter.Null is a singleton, not thread-safe for concurrent access
  3. Multiple threads writing to both streams cause IndexOutOfRangeException
  4. Console output goes nowhere in these environments anyway

Fixes #7691

Checklist

For significant changes, please ensure that the following have been completed (delete if not relevant):

- Detect when running in IIS/Windows Service environments where Console.Out
  and Console.Error are redirected to the same StreamWriter.Null singleton
- Skip console output entirely in these environments to prevent race conditions
  that cause IndexOutOfRangeException and cascade failures
- Improve DefaultLogger error handling to prevent feedback loops
- Add unit tests for non-console scenarios

The race condition occurs because:
1. IIS/Services redirect both Console.Out and Console.Error to StreamWriter.Null
2. StreamWriter.Null is a singleton, not thread-safe for concurrent access
3. Multiple threads writing to both streams cause IndexOutOfRangeException
4. Console output goes nowhere in these environments anyway

Fixes akkadotnet#7691
@Aaronontheweb Aaronontheweb added this to the 1.5.48 milestone Sep 2, 2025
@Aaronontheweb Aaronontheweb modified the milestones: 1.5.48, 1.5.49 Sep 2, 2025
- Make console detection more precise: only skip output when both Console.Out
  AND Console.Error point to StreamWriter.Null (the exact race condition scenario)
- Remove unnecessary try-catch in DefaultLogger.Print() since Tell() is unlikely to throw
- Keep improved error message for debugging when logger is not initialized
Copy link
Member Author

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

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

Detailed my changes

}

[Fact]
public void StandardOutWriter_should_handle_concurrent_writes_without_race_conditions()
Copy link
Member Author

Choose a reason for hiding this comment

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

This whole test class is probably a tad useless IMHO given the racy and rare nature of this bug but it's worth a shot

}

[Fact]
public void StandardOutWriter_should_handle_null_and_empty_messages()
Copy link
Member Author

Choose a reason for hiding this comment

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

Probably the most useful test of the bunch tbh

// and Console.Error point to the SAME StreamWriter.Null singleton instance.
// This is the exact condition that causes the race condition.
// Note: We check both because in these environments, both are always set to the same instance
if (Console.Out == StreamWriter.Null && Console.Error == StreamWriter.Null)
Copy link
Member Author

Choose a reason for hiding this comment

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

Comment in the code explains it best

Copy link
Contributor

@Arkatufus Arkatufus left a comment

Choose a reason for hiding this comment

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

LGTM

@Aaronontheweb Aaronontheweb merged commit dceca50 into akkadotnet:v1.5 Sep 4, 2025
7 of 11 checks passed
@Aaronontheweb Aaronontheweb deleted the fix/7691-iis-console-race-condition branch September 4, 2025 13:46
Aaronontheweb added a commit to Aaronontheweb/akka.net that referenced this pull request Sep 4, 2025
…adotnet#7793)

* Fix IIS/Windows Service console race condition (akkadotnet#7691)

- Detect when running in IIS/Windows Service environments where Console.Out
  and Console.Error are redirected to the same StreamWriter.Null singleton
- Skip console output entirely in these environments to prevent race conditions
  that cause IndexOutOfRangeException and cascade failures
- Improve DefaultLogger error handling to prevent feedback loops
- Add unit tests for non-console scenarios

The race condition occurs because:
1. IIS/Services redirect both Console.Out and Console.Error to StreamWriter.Null
2. StreamWriter.Null is a singleton, not thread-safe for concurrent access
3. Multiple threads writing to both streams cause IndexOutOfRangeException
4. Console output goes nowhere in these environments anyway

Fixes akkadotnet#7691

* Refine console detection and simplify error handling

- Make console detection more precise: only skip output when both Console.Out
  AND Console.Error point to StreamWriter.Null (the exact race condition scenario)
- Remove unnecessary try-catch in DefaultLogger.Print() since Tell() is unlikely to throw
- Keep improved error message for debugging when logger is not initialized
Aaronontheweb added a commit that referenced this pull request Sep 5, 2025
* Fix IIS/Windows Service console race condition (#7691)

- Detect when running in IIS/Windows Service environments where Console.Out
  and Console.Error are redirected to the same StreamWriter.Null singleton
- Skip console output entirely in these environments to prevent race conditions
  that cause IndexOutOfRangeException and cascade failures
- Improve DefaultLogger error handling to prevent feedback loops
- Add unit tests for non-console scenarios

The race condition occurs because:
1. IIS/Services redirect both Console.Out and Console.Error to StreamWriter.Null
2. StreamWriter.Null is a singleton, not thread-safe for concurrent access
3. Multiple threads writing to both streams cause IndexOutOfRangeException
4. Console output goes nowhere in these environments anyway

Fixes #7691

* Refine console detection and simplify error handling

- Make console detection more precise: only skip output when both Console.Out
  AND Console.Error point to StreamWriter.Null (the exact race condition scenario)
- Remove unnecessary try-catch in DefaultLogger.Print() since Tell() is unlikely to throw
- Keep improved error message for debugging when logger is not initialized
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants