Clean up SDK pending calls and notification callbacks on future drop
Preserve late lock-grant release separately, and drop callback captures outside transport state borrows. Document process-lifetime host watches. Card: SAU-391
This commit is contained in:
@@ -98,6 +98,36 @@ impl Probe {
|
||||
.await
|
||||
}
|
||||
|
||||
/// Drop one watch while another still delivers, in a process that remains alive.
|
||||
async fn drop_watch(&self) -> Result<Vec<String>> {
|
||||
use std::{cell::RefCell, future::IntoFuture, rc::Rc, task::Poll};
|
||||
let events = Rc::new(RefCell::new(Vec::new()));
|
||||
let captured = events.clone();
|
||||
let mut dropped = call("core.watch", json!({"path":"/dropped"}))
|
||||
.on_notify(move |_, _| captured.borrow_mut().push("dropped".to_owned()))
|
||||
.into_future();
|
||||
std::future::poll_fn(|cx| {
|
||||
assert!(dropped.as_mut().poll(cx).is_pending());
|
||||
Poll::Ready(())
|
||||
})
|
||||
.await;
|
||||
drop(dropped);
|
||||
let captured = events.clone();
|
||||
let mut kept = call("core.watch", json!({"path":"/kept"}))
|
||||
.on_notify(move |name, _| captured.borrow_mut().push(name.to_owned()))
|
||||
.into_future();
|
||||
std::future::poll_fn(|cx| {
|
||||
assert!(kept.as_mut().poll(cx).is_pending());
|
||||
Poll::Ready(())
|
||||
})
|
||||
.await;
|
||||
// The harness sends late traffic and kept-watch events before answering.
|
||||
call("other.barrier", json!({})).await?;
|
||||
drop(kept);
|
||||
let result = events.borrow().clone();
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Publish a control endpoint until EOF.
|
||||
async fn serve(&self) -> Result<()> {
|
||||
sausage_plugin::listen("/endpoint", std::rc::Rc::new(Control)).await
|
||||
|
||||
@@ -117,6 +117,25 @@ fn protocol() {
|
||||
p.send(json!({"jsonrpc":"2.0","method":"core.notify","params":{"call":watch["id"],"name":"armed","params":{}}}));
|
||||
assert_eq!(p.read()["result"], Value::Null);
|
||||
p.finishes();
|
||||
// Keep the process alive after dropping a call: late traffic is ignored,
|
||||
// while the kept watch continues to deliver every notification.
|
||||
let mut p = start(&wasm, &dir);
|
||||
p.request("drop_watch", json!({}));
|
||||
let dropped = p.read();
|
||||
let kept = p.read();
|
||||
let barrier = p.read();
|
||||
assert_eq!(dropped["params"]["path"], "/dropped");
|
||||
assert_eq!(kept["params"]["path"], "/kept");
|
||||
assert_eq!(barrier["method"], "other.barrier");
|
||||
for watch in [&dropped, &kept] {
|
||||
for name in ["armed", "changed", "changed"] {
|
||||
p.send(json!({"jsonrpc":"2.0","method":"core.notify","params":{"call":watch["id"],"name":name,"params":{}}}));
|
||||
}
|
||||
}
|
||||
p.answer(&dropped, Value::Null);
|
||||
p.answer(&barrier, json!({}));
|
||||
assert_eq!(p.read()["result"], json!(["armed", "changed", "changed"]));
|
||||
p.finishes();
|
||||
let mut p = start(&wasm, &dir);
|
||||
p.request("rpc.discover", json!({}));
|
||||
let d = p.read();
|
||||
|
||||
Reference in New Issue
Block a user