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:
parent
82afacd33d
commit
d4fe1115e7
7 changed files with 341 additions and 472 deletions
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue