## Motivation and Context
`cleanup_session_unsafe` was closing streams inside the mutex, which could block all session
operations if `stream.close` is slow or blocks (e.g., waiting for network I/O).
The original `reap_expired_sessions` avoided this by closing streams outside the mutex,
but the other 6 call sites of `cleanup_session_unsafe` did not, creating an inconsistency.
This change separates stream closing from session deletion. `cleanup_session_unsafe`
now only removes the session from `@sessions` and returns it.
All callers close streams outside the mutex via `close_stream_safely`,
ensuring consistent behavior and preventing mutex contention from blocking I/O.
## How Has This Been Tested?
Added tests that verify streams are closed outside the mutex by using `Mutex#try_lock`
inside mock stream close callbacks:
- `reap_expired_sessions closes stream outside mutex`
- `send_notification closes stream outside mutex on write error`
## Breaking Changes
None. This is an internal improvement with no change to public API behavior.