Skip to content

Commit 2d04306

Browse files
fix(iroh-net): use try_send rather than send so we dont block the local swarm discovery service (#2794)
## Description Using `subscriber.send().await` could block the entire discovery service if one of the subscribers polls too slow. Change to `try_send` that will drop the discovery item from that stream if it is closed. ## Notes & open questions Added a line in the documentation to mention that if you do not poll enough, you may miss messages. ## Change checklist - [x] Self-review. - [x] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. --------- Co-authored-by: Diva M <[email protected]>
1 parent c349c43 commit 2d04306

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

iroh-net/src/discovery.rs

+2
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ pub trait Discovery: std::fmt::Debug + Send + Sync {
158158
/// until the stream is actually polled. To avoid missing discovered nodes,
159159
/// poll the stream as soon as possible.
160160
///
161+
/// If you do not regularly poll the stream, you may miss discovered nodes.
162+
///
161163
/// Any discovery systems that only discover when explicitly resolving a
162164
/// specific [`NodeId`] do not need to implement this method. Any nodes or
163165
/// addresses that are discovered by calling `resolve` should NOT be added

iroh-net/src/discovery/local_swarm_discovery.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ use watchable::Watchable;
4747

4848
use iroh_base::key::PublicKey;
4949
use swarm_discovery::{Discoverer, DropGuard, IpClass, Peer};
50-
use tokio::{sync::mpsc, task::JoinSet};
50+
use tokio::{
51+
sync::mpsc::{self, error::TrySendError},
52+
task::JoinSet,
53+
};
5154
use tokio_util::task::AbortOnDropHandle;
5255

5356
use crate::{
@@ -103,12 +106,21 @@ impl Subscribers {
103106
/// Sends the `node_id` and `item` to each subscriber.
104107
///
105108
/// Cleans up any subscribers that have been dropped.
106-
async fn send(&mut self, item: DiscoveryItem) {
109+
fn send(&mut self, item: DiscoveryItem) {
107110
let mut clean_up = vec![];
108111
for (i, subscriber) in self.0.iter().enumerate() {
109112
// assume subscriber was dropped
110-
if (subscriber.send(item.clone()).await).is_err() {
111-
clean_up.push(i);
113+
if let Err(err) = subscriber.try_send(item.clone()) {
114+
match err {
115+
TrySendError::Full(_) => {
116+
warn!(
117+
?item,
118+
idx = i,
119+
"local swarm discovery subscriber is blocked, dropping item"
120+
)
121+
}
122+
TrySendError::Closed(_) => clean_up.push(i),
123+
}
112124
}
113125
}
114126
for i in clean_up.into_iter().rev() {
@@ -236,7 +248,7 @@ impl LocalSwarmDiscovery {
236248
// in other words, nodes sent to the `subscribers` should only be the ones that
237249
// have been "passively" discovered
238250
if !resolved {
239-
subscribers.send(item).await;
251+
subscribers.send(item);
240252
}
241253
}
242254
Message::Resolve(node_id, sender) => {

0 commit comments

Comments
 (0)