fix(remoteingress-core): guard tunnel frame sends with cancellation to prevent async send deadlocks
This commit is contained in:
@@ -445,7 +445,10 @@ async fn handle_hub_frame(
|
||||
// Send final window update for remaining consumed bytes
|
||||
if consumed_since_update > 0 {
|
||||
let frame = encode_window_update(stream_id, FRAME_WINDOW_UPDATE_BACK, consumed_since_update);
|
||||
let _ = wub_tx.send(frame).await;
|
||||
tokio::select! {
|
||||
_ = wub_tx.send(frame) => {}
|
||||
_ = writer_token.cancelled() => {}
|
||||
}
|
||||
}
|
||||
let _ = up_write.shutdown().await;
|
||||
});
|
||||
@@ -511,10 +514,13 @@ async fn handle_hub_frame(
|
||||
}
|
||||
|
||||
// Send CLOSE_BACK via DATA channel (must arrive AFTER last DATA_BACK).
|
||||
// Use send().await to guarantee delivery (try_send silently drops if full).
|
||||
// select! with cancellation guard prevents indefinite blocking if tunnel dies.
|
||||
if !stream_token.is_cancelled() {
|
||||
let close_frame = encode_frame(stream_id, FRAME_CLOSE_BACK, &[]);
|
||||
let _ = data_writer_tx.send(close_frame).await;
|
||||
tokio::select! {
|
||||
_ = data_writer_tx.send(close_frame) => {}
|
||||
_ = stream_token.cancelled() => {}
|
||||
}
|
||||
}
|
||||
|
||||
writer_for_edge_data.abort();
|
||||
@@ -525,15 +531,21 @@ async fn handle_hub_frame(
|
||||
if let Err(e) = result {
|
||||
log::error!("Stream {} error: {}", stream_id, e);
|
||||
// Send CLOSE_BACK via DATA channel on error (must arrive after any DATA_BACK).
|
||||
// Use send().await to guarantee delivery.
|
||||
if !stream_token.is_cancelled() {
|
||||
let close_frame = encode_frame(stream_id, FRAME_CLOSE_BACK, &[]);
|
||||
let _ = data_writer_tx.send(close_frame).await;
|
||||
tokio::select! {
|
||||
_ = data_writer_tx.send(close_frame) => {}
|
||||
_ = stream_token.cancelled() => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signal main loop to remove stream from the map
|
||||
let _ = cleanup.send(stream_id).await;
|
||||
// Signal main loop to remove stream from the map.
|
||||
// Cancellation guard prevents indefinite blocking if cleanup channel is full.
|
||||
tokio::select! {
|
||||
_ = cleanup.send(stream_id) => {}
|
||||
_ = stream_token.cancelled() => {}
|
||||
}
|
||||
stream_counter.fetch_sub(1, Ordering::Relaxed);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user