Use an unbounded channel for peer's outgoing messages

Using a bounded channel may have blocked the collaboration server
from making progress handling RPC traffic.

There's no need to apply backpressure to calling code within the
same process - suspending a task that is attempting to call `send` has
an even greater memory cost than just buffering a protobuf message.

We do still want a bounded channel for incoming messages, so that
we provide backpressure to noisy peers - blocking their writes as opposed
to allowing them to buffer arbitrarily many messages in our server.

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2022-02-07 12:27:13 -08:00
parent 82afacd33d
commit d4fe1115e7
7 changed files with 341 additions and 472 deletions

View file

@ -17,7 +17,7 @@ use std::{
};
use sum_tree::{Bias, SumTree};
use time::OffsetDateTime;
use util::{post_inc, TryFutureExt};
use util::{post_inc, ResultExt as _, TryFutureExt};
pub struct ChannelList {
available_channels: Option<Vec<ChannelDetails>>,
@ -168,16 +168,12 @@ impl ChannelList {
impl Entity for Channel {
type Event = ChannelEvent;
fn release(&mut self, cx: &mut MutableAppContext) {
let rpc = self.rpc.clone();
let channel_id = self.details.id;
cx.foreground()
.spawn(async move {
if let Err(error) = rpc.send(proto::LeaveChannel { channel_id }).await {
log::error!("error leaving channel: {}", error);
};
fn release(&mut self, _: &mut MutableAppContext) {
self.rpc
.send(proto::LeaveChannel {
channel_id: self.details.id,
})
.detach()
.log_err();
}
}
@ -718,18 +714,16 @@ mod tests {
});
// Receive a new message.
server
.send(proto::ChannelMessageSent {
channel_id: channel.read_with(&cx, |channel, _| channel.details.id),
message: Some(proto::ChannelMessage {
id: 12,
body: "c".into(),
timestamp: 1002,
sender_id: 7,
nonce: Some(3.into()),
}),
})
.await;
server.send(proto::ChannelMessageSent {
channel_id: channel.read_with(&cx, |channel, _| channel.details.id),
message: Some(proto::ChannelMessage {
id: 12,
body: "c".into(),
timestamp: 1002,
sender_id: 7,
nonce: Some(3.into()),
}),
});
// Client requests user for message since they haven't seen them yet
let get_users = server.receive::<proto::GetUsers>().await.unwrap();

View file

@ -24,7 +24,6 @@ use std::{
collections::HashMap,
convert::TryFrom,
fmt::Write as _,
future::Future,
sync::{Arc, Weak},
time::{Duration, Instant},
};
@ -677,8 +676,8 @@ impl Client {
}
}
pub async fn send<T: EnvelopedMessage>(&self, message: T) -> Result<()> {
self.peer.send(self.connection_id()?, message).await
pub fn send<T: EnvelopedMessage>(&self, message: T) -> Result<()> {
self.peer.send(self.connection_id()?, message)
}
pub async fn request<T: RequestMessage>(&self, request: T) -> Result<T::Response> {
@ -689,7 +688,7 @@ impl Client {
&self,
receipt: Receipt<T>,
response: T::Response,
) -> impl Future<Output = Result<()>> {
) -> Result<()> {
self.peer.respond(receipt, response)
}
@ -697,7 +696,7 @@ impl Client {
&self,
receipt: Receipt<T>,
error: proto::Error,
) -> impl Future<Output = Result<()>> {
) -> Result<()> {
self.peer.respond_with_error(receipt, error)
}
}
@ -860,8 +859,8 @@ mod tests {
});
drop(subscription3);
server.send(proto::UnshareProject { project_id: 1 }).await;
server.send(proto::UnshareProject { project_id: 2 }).await;
server.send(proto::UnshareProject { project_id: 1 });
server.send(proto::UnshareProject { project_id: 2 });
done_rx1.next().await.unwrap();
done_rx2.next().await.unwrap();
}
@ -890,7 +889,7 @@ mod tests {
Ok(())
})
});
server.send(proto::Ping {}).await;
server.send(proto::Ping {});
done_rx2.next().await.unwrap();
}
@ -914,7 +913,7 @@ mod tests {
},
));
});
server.send(proto::Ping {}).await;
server.send(proto::Ping {});
done_rx.next().await.unwrap();
}

View file

@ -118,8 +118,8 @@ impl FakeServer {
self.forbid_connections.store(false, SeqCst);
}
pub async fn send<T: proto::EnvelopedMessage>(&self, message: T) {
self.peer.send(self.connection_id(), message).await.unwrap();
pub fn send<T: proto::EnvelopedMessage>(&self, message: T) {
self.peer.send(self.connection_id(), message).unwrap();
}
pub async fn receive<M: proto::EnvelopedMessage>(&self) -> Result<TypedEnvelope<M>> {
@ -148,7 +148,7 @@ impl FakeServer {
receipt: Receipt<T>,
response: T::Response,
) {
self.peer.respond(receipt, response).await.unwrap()
self.peer.respond(receipt, response).unwrap()
}
fn connection_id(&self) -> ConnectionId {