Merge pull request '0.2.1: release handlers on close to fix a per-connection leak' (#2) from release-handlers-on-close into master
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
Generated
+1
-1
@@ -895,7 +895,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "session-rs"
|
name = "session-rs"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "session-rs"
|
name = "session-rs"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A lightweight async request/response and notification protocol over WebSockets"
|
description = "A lightweight async request/response and notification protocol over WebSockets"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|||||||
+6
-1
@@ -431,10 +431,15 @@ impl Session {
|
|||||||
// Dropping the senders fails every waiting `request`.
|
// Dropping the senders fails every waiting `request`.
|
||||||
drop(std::mem::take(&mut *self.inner.pending.lock().unwrap()));
|
drop(std::mem::take(&mut *self.inner.pending.lock().unwrap()));
|
||||||
|
|
||||||
let handler = self.inner.on_close.lock().unwrap().clone();
|
let handler = self.inner.on_close.lock().unwrap().take();
|
||||||
if let Some(handler) = handler {
|
if let Some(handler) = handler {
|
||||||
let _ = handler().await;
|
let _ = handler().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handlers usually capture a clone of this session; dropping them
|
||||||
|
// breaks that cycle so the session can be freed.
|
||||||
|
self.inner.requests.lock().unwrap().clear();
|
||||||
|
self.inner.notifications.lock().unwrap().clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -450,3 +450,43 @@ async fn axum_adapter_serves_sessions_next_to_http_routes() {
|
|||||||
tcp.read_to_string(&mut body).await.unwrap();
|
tcp.read_to_string(&mut body).await.unwrap();
|
||||||
assert!(body.starts_with("HTTP/1.1 200") && body.ends_with("ok"), "{body}");
|
assert!(body.starts_with("HTTP/1.1 200") && body.ends_with("ok"), "{body}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn closing_releases_handlers_that_capture_the_session() {
|
||||||
|
let client = connect(start_server().await).await;
|
||||||
|
let captured = Arc::new(());
|
||||||
|
|
||||||
|
// Handlers typically hold a clone of their own session; that must not keep
|
||||||
|
// the session (and everything the handlers capture) alive after close.
|
||||||
|
client
|
||||||
|
.on_request::<Silent, _>({
|
||||||
|
let session = client.clone();
|
||||||
|
let captured = captured.clone();
|
||||||
|
move |_, ()| {
|
||||||
|
let _ = (&session, &captured);
|
||||||
|
async { Ok(()) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
client
|
||||||
|
.on_close({
|
||||||
|
let session = client.clone();
|
||||||
|
let captured = captured.clone();
|
||||||
|
move || {
|
||||||
|
let _ = (&session, &captured);
|
||||||
|
async { Ok(()) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
assert_eq!(Arc::strong_count(&captured), 3);
|
||||||
|
|
||||||
|
client.close().await.unwrap();
|
||||||
|
|
||||||
|
tokio::time::timeout(WAIT, async {
|
||||||
|
while Arc::strong_count(&captured) > 1 {
|
||||||
|
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("handlers were not released after close");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user