fix: enhance transport graceful shutdown with proper writer closure (#392)
- Add TransportWriter type alias for cleaner type definitions - Wrap transport writer in Option to enable proper closure - Implement close() method to drop writer and signal end of communication - Update graceful_shutdown to close transport before waiting for process exit - Improve error handling for closed transport state Addresses the graceful shutdown improvements discussed in #347 and #364
This commit is contained in:
parent
a84a3eb79b
commit
d328157be3
2 changed files with 19 additions and 5 deletions
|
|
@ -42,9 +42,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub type TransportWriter<Role, W> = FramedWrite<W, JsonRpcMessageCodec<TxJsonRpcMessage<Role>>>;
|
||||
|
||||
pub struct AsyncRwTransport<Role: ServiceRole, R: AsyncRead, W: AsyncWrite> {
|
||||
read: FramedRead<R, JsonRpcMessageCodec<RxJsonRpcMessage<Role>>>,
|
||||
write: Arc<Mutex<FramedWrite<W, JsonRpcMessageCodec<TxJsonRpcMessage<Role>>>>>,
|
||||
write: Arc<Mutex<Option<TransportWriter<Role, W>>>>,
|
||||
}
|
||||
|
||||
impl<Role: ServiceRole, R, W> AsyncRwTransport<Role, R, W>
|
||||
|
|
@ -57,10 +59,10 @@ where
|
|||
read,
|
||||
JsonRpcMessageCodec::<RxJsonRpcMessage<Role>>::default(),
|
||||
);
|
||||
let write = Arc::new(Mutex::new(FramedWrite::new(
|
||||
let write = Arc::new(Mutex::new(Some(FramedWrite::new(
|
||||
write,
|
||||
JsonRpcMessageCodec::<TxJsonRpcMessage<Role>>::default(),
|
||||
)));
|
||||
))));
|
||||
Self { read, write }
|
||||
}
|
||||
}
|
||||
|
|
@ -103,7 +105,14 @@ where
|
|||
let lock = self.write.clone();
|
||||
async move {
|
||||
let mut write = lock.lock().await;
|
||||
write.send(item).await.map_err(Into::into)
|
||||
if let Some(ref mut write) = *write {
|
||||
write.send(item).await.map_err(Into::into)
|
||||
} else {
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotConnected,
|
||||
"Transport is closed",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +129,8 @@ where
|
|||
}
|
||||
|
||||
async fn close(&mut self) -> Result<(), Self::Error> {
|
||||
let mut write = self.write.lock().await;
|
||||
drop(write.take());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,10 +104,13 @@ impl TokioChildProcess {
|
|||
|
||||
/// Gracefully shutdown the child process
|
||||
///
|
||||
/// This will first wait for the child process to exit normally with a timeout.
|
||||
/// This will first close the transport to the child process (the server),
|
||||
/// and wait for the child process to exit normally with a timeout.
|
||||
/// If the child process doesn't exit within the timeout, it will be killed.
|
||||
pub async fn graceful_shutdown(&mut self) -> std::io::Result<()> {
|
||||
if let Some(mut child) = self.child.inner.take() {
|
||||
self.transport.close().await?;
|
||||
|
||||
let wait_fut = Box::into_pin(child.wait());
|
||||
tokio::select! {
|
||||
_ = tokio::time::sleep(std::time::Duration::from_secs(MAX_WAIT_ON_DROP_SECS)) => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue