Handlers usually capture a clone of their own Session, for example to remove it from a map in on_close or to call notify. Because the Session owns those handlers, the two kept each other alive forever. A closed session, and everything its handlers captured, was never freed. The socket itself did close, but a small amount of memory leaked per connection. 0.1.x had the same leak.
The fix is in shutdown, which still runs exactly once:
the on_close handler is now taken out and run, instead of cloned and run
the request and notification handlers are then cleared
Requests still queued after close already failed to send, so behaviour doesn't change.
The version is bumped to 0.2.1.
Testing
New test closing_releases_handlers_that_capture_the_session. It registers a request handler and an on_close handler that both capture the session and a sentinel Arc, closes the session, and waits for the sentinel to be released. It fails on master (times out after 5 s) and passes with this change.
All 14 tests pass on 10 of 10 runs of cargo test --all-features.
Clippy is clean and cargo publish --dry-run passes.
## Summary
Handlers usually capture a clone of their own `Session`, for example to remove it from a map in `on_close` or to call `notify`. Because the `Session` owns those handlers, the two kept each other alive forever. A closed session, and everything its handlers captured, was never freed. The socket itself did close, but a small amount of memory leaked per connection. 0.1.x had the same leak.
The fix is in `shutdown`, which still runs exactly once:
- the `on_close` handler is now taken out and run, instead of cloned and run
- the request and notification handlers are then cleared
Requests still queued after close already failed to send, so behaviour doesn't change.
The version is bumped to 0.2.1.
## Testing
- New test `closing_releases_handlers_that_capture_the_session`. It registers a request handler and an `on_close` handler that both capture the session and a sentinel `Arc`, closes the session, and waits for the sentinel to be released. It **fails on master** (times out after 5 s) and passes with this change.
- All 14 tests pass on 10 of 10 runs of `cargo test --all-features`.
- Clippy is clean and `cargo publish --dry-run` passes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Handlers commonly capture a clone of their own Session, and the Session
owns its handlers, so a closed session was never freed. On shutdown,
take the on_close handler instead of cloning it and clear the request
and notification handlers after it runs.
Bump to 0.2.1.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Handlers usually capture a clone of their own
Session, for example to remove it from a map inon_closeor to callnotify. Because theSessionowns those handlers, the two kept each other alive forever. A closed session, and everything its handlers captured, was never freed. The socket itself did close, but a small amount of memory leaked per connection. 0.1.x had the same leak.The fix is in
shutdown, which still runs exactly once:on_closehandler is now taken out and run, instead of cloned and runRequests still queued after close already failed to send, so behaviour doesn't change.
The version is bumped to 0.2.1.
Testing
closing_releases_handlers_that_capture_the_session. It registers a request handler and anon_closehandler that both capture the session and a sentinelArc, closes the session, and waits for the sentinel to be released. It fails on master (times out after 5 s) and passes with this change.cargo test --all-features.cargo publish --dry-runpasses.🤖 Generated with Claude Code