the call outcome now rides the frame as Result<Response, WireError>, so a rejection reaches the caller with its message and the pooled connection stays up. only a real transport failure closes it now; a malformed request comes back as a rejection too.
43 lines
1.3 KiB
Rust
43 lines
1.3 KiB
Rust
use std::sync::Arc;
|
|
use service_rpc::{serve, RpcClient, RpcError, RpcResult, RpcService};
|
|
use tokio::net::TcpListener;
|
|
|
|
struct Doubler;
|
|
|
|
#[async_trait::async_trait]
|
|
impl RpcService for Doubler {
|
|
type Request = i32;
|
|
type Response = i32;
|
|
fn service_name(&self) -> &'static str {
|
|
"doubler"
|
|
}
|
|
async fn call(&self, request: i32) -> RpcResult<i32> {
|
|
if request == 0 {
|
|
return Err(RpcError::Rejected("zero is not allowed".to_owned()));
|
|
}
|
|
Ok(request * 2)
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn a_service_error_reaches_the_caller_and_keeps_the_connection() {
|
|
let listener = TcpListener::bind("127.0.0.1:0").await.expect("bind");
|
|
let endpoint = listener.local_addr().expect("addr").to_string();
|
|
tokio::spawn(async move {
|
|
let _ = serve(listener, Arc::new(Doubler)).await;
|
|
});
|
|
|
|
let client: RpcClient<i32, i32> = RpcClient::with_pool_size(endpoint, 1);
|
|
|
|
assert_eq!(client.call(&5).await.expect("ok call"), 10);
|
|
|
|
match client.call(&0).await {
|
|
Err(RpcError::Rejected(message)) => assert_eq!(message, "zero is not allowed"),
|
|
other => panic!("expected a rejection, got {other:?}"),
|
|
}
|
|
|
|
assert_eq!(
|
|
client.call(&7).await.expect("connection survived the error"),
|
|
14
|
|
);
|
|
}
|