Fix: Suppress expected socket errors during intentional shutdown #21
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.
Fix spurious socket error logging during intentional shutdown
Fixes #11
Problem
When the application shuts down (e.g., via Ctrl+C or calling
terminate()), the socket/pipe threads are often blocked inrecv()orrecv_bytes()calls. Whenstop()closes the socket, this causesOSError: [Errno 9] Bad file descriptor(on Unix) or similar errors (on Windows) to be logged, even though this is expected behavior during intentional shutdown.Example Error Log
This error appears intermittently during normal shutdown due to a race condition:
stop()→ closes socketrecv()→ raisesOSErrorwhen socket closesImpact
Solution
Add a
_stoppingflag to bothUnixSocketandWindowsSocketclasses to distinguish between intentional shutdown and unexpected disconnection:self._stopping = Falsein__init__()self._stopping = Trueinstop()before closing socketrun()exception handler, only log ifnot self._stoppingCode Changes
UnixSocket class:
__init__: Addedself._stopping = False(line 144)stop(): Addedself._stopping = Truebefore closing (line 155)run(): Changed error logging toif not self._stopping:(lines 193-195)WindowsSocket class:
__init__: Addedself._stopping = False(line 55)stop(): Addedself._stopping = Truebefore closing (line 79)run(): Changed error logging toif not self._stopping:(lines 121-123)Why This Works
The flag is set before closing the socket, ensuring the socket thread sees it when the exception occurs. This creates a happens-before relationship:
Testing
Tested with jellyfin-mpv-shim on macOS (external MPV mode):
Test Scenarios
✅ Ctrl+C shutdown: Clean exit, no "Bad file descriptor" error
✅ Normal stop operations: No spurious errors logged
✅ Playback stop/start cycles: Clean transitions
✅ Unexpected errors preserved: Flag remains
Falsefor actual connection issuesBefore Fix
After Fix
Clean shutdown with no spurious errors! 🎉
Backward Compatibility
✅ No breaking changes: Only internal implementation detail
✅ No API changes: Public interface remains identical
✅ No performance impact: Single boolean flag check
✅ Thread-safe: Flag is set before socket operations
Alternative Approaches Considered
OSErroris legitimate for both casesThe flag-based approach is the cleanest solution that preserves error visibility while eliminating false positives.
Related Issues
This pattern is common in socket-based threading code. Similar fixes have been implemented in other projects:
socketservermodule uses shutdown flagsChecklist