Skip to content

Commit 918c25a

Browse files
ciriasSirius Fang
andauthored
feat: Replace unbounded channel with bounded (#312)
Co-authored-by: Sirius Fang <sirius@secondspectrum.com>
1 parent ed4914a commit 918c25a

6 files changed

Lines changed: 70 additions & 19 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ description = "Rust client for Apache Pulsar"
1616
keywords = ["pulsar", "api", "client"]
1717

1818
[dependencies]
19+
async-channel = "2"
1920
bytes = "^1.4.0"
2021
crc = "^3.0.1"
2122
nom = { version="^7.1.3", default-features=false, features=["alloc"] }

src/client.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,20 @@ impl<Exe: Executor> Pulsar<Exe> {
179179
connection_retry_parameters: Option<ConnectionRetryOptions>,
180180
operation_retry_parameters: Option<OperationRetryOptions>,
181181
tls_options: Option<TlsOptions>,
182+
outbound_channel_size: Option<usize>,
182183
executor: Exe,
183184
) -> Result<Self, Error> {
184185
let url: String = url.into();
185186
let executor = Arc::new(executor);
186187
let operation_retry_options = operation_retry_parameters.unwrap_or_default();
188+
let outbound_channel_size = outbound_channel_size.unwrap_or(100);
187189
let manager = ConnectionManager::new(
188190
url,
189191
auth,
190192
connection_retry_parameters,
191193
operation_retry_options.clone(),
192194
tls_options,
195+
outbound_channel_size,
193196
executor.clone(),
194197
)
195198
.await?;
@@ -252,6 +255,7 @@ impl<Exe: Executor> Pulsar<Exe> {
252255
connection_retry_options: None,
253256
operation_retry_options: None,
254257
tls_options: None,
258+
outbound_channel_size: None,
255259
executor,
256260
}
257261
}
@@ -452,6 +456,7 @@ pub struct PulsarBuilder<Exe: Executor> {
452456
connection_retry_options: Option<ConnectionRetryOptions>,
453457
operation_retry_options: Option<OperationRetryOptions>,
454458
tls_options: Option<TlsOptions>,
459+
outbound_channel_size: Option<usize>,
455460
executor: Exe,
456461
}
457462

@@ -549,6 +554,12 @@ impl<Exe: Executor> PulsarBuilder<Exe> {
549554
Ok(self.with_certificate_chain(v))
550555
}
551556

557+
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
558+
pub fn with_outbound_channel_size(mut self, size: usize) -> Result<Self, std::io::Error> {
559+
self.outbound_channel_size = Some(size);
560+
Ok(self)
561+
}
562+
552563
/// creates the Pulsar client and connects it
553564
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
554565
pub async fn build(self) -> Result<Pulsar<Exe>, Error> {
@@ -558,6 +569,7 @@ impl<Exe: Executor> PulsarBuilder<Exe> {
558569
connection_retry_options,
559570
operation_retry_options,
560571
tls_options,
572+
outbound_channel_size,
561573
executor,
562574
} = self;
563575

@@ -567,6 +579,7 @@ impl<Exe: Executor> PulsarBuilder<Exe> {
567579
connection_retry_options,
568580
operation_retry_options,
569581
tls_options,
582+
outbound_channel_size,
570583
executor,
571584
)
572585
.await

src/connection.rs

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ impl crate::authentication::Authentication for Authentication {
9999

100100
pub(crate) struct Receiver<S: Stream<Item = Result<Message, ConnectionError>>> {
101101
inbound: Pin<Box<S>>,
102-
outbound: mpsc::UnboundedSender<Message>,
102+
outbound: async_channel::Sender<Message>,
103103
error: SharedError,
104104
pending_requests: BTreeMap<RequestKey, oneshot::Sender<Message>>,
105105
consumers: BTreeMap<u64, mpsc::UnboundedSender<Message>>,
@@ -114,7 +114,7 @@ impl<S: Stream<Item = Result<Message, ConnectionError>>> Receiver<S> {
114114
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
115115
pub fn new(
116116
inbound: S,
117-
outbound: mpsc::UnboundedSender<Message>,
117+
outbound: async_channel::Sender<Message>,
118118
error: SharedError,
119119
registrations: mpsc::UnboundedReceiver<Register>,
120120
shutdown: oneshot::Receiver<()>,
@@ -187,7 +187,9 @@ impl<S: Stream<Item = Result<Message, ConnectionError>>> Future for Receiver<S>
187187
command: BaseCommand { ping: Some(_), .. },
188188
..
189189
} => {
190-
let _ = self.outbound.unbounded_send(messages::pong());
190+
if let Err(e) = self.outbound.try_send(messages::pong()) {
191+
error!("failed to send pong: {}", e);
192+
}
191193
}
192194
Message {
193195
command: BaseCommand { pong: Some(_), .. },
@@ -289,7 +291,7 @@ impl SerialId {
289291
//#[derive(Clone)]
290292
pub struct ConnectionSender<Exe: Executor> {
291293
connection_id: Uuid,
292-
tx: mpsc::UnboundedSender<Message>,
294+
tx: async_channel::Sender<Message>,
293295
registrations: mpsc::UnboundedSender<Register>,
294296
receiver_shutdown: Option<oneshot::Sender<()>>,
295297
request_id: SerialId,
@@ -302,7 +304,7 @@ impl<Exe: Executor> ConnectionSender<Exe> {
302304
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
303305
pub(crate) fn new(
304306
connection_id: Uuid,
305-
tx: mpsc::UnboundedSender<Message>,
307+
tx: async_channel::Sender<Message>,
306308
registrations: mpsc::UnboundedSender<Register>,
307309
receiver_shutdown: oneshot::Sender<()>,
308310
request_id: SerialId,
@@ -349,9 +351,9 @@ impl<Exe: Executor> ConnectionSender<Exe> {
349351
match (
350352
self.registrations
351353
.unbounded_send(Register::Ping { resolver }),
352-
self.tx.unbounded_send(messages::ping()),
354+
self.tx.try_send(messages::ping())?,
353355
) {
354-
(Ok(_), Ok(_)) => {
356+
(Ok(_), ()) => {
355357
let delay_f = self.executor.delay(self.operation_timeout);
356358
pin_mut!(response);
357359
pin_mut!(delay_f);
@@ -526,8 +528,8 @@ impl<Exe: Executor> ConnectionSender<Exe> {
526528
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
527529
pub fn send_flow(&self, consumer_id: u64, message_permits: u32) -> Result<(), ConnectionError> {
528530
self.tx
529-
.unbounded_send(messages::flow(consumer_id, message_permits))
530-
.map_err(|_| ConnectionError::Disconnected)
531+
.try_send(messages::flow(consumer_id, message_permits))?;
532+
Ok(())
531533
}
532534

533535
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
@@ -538,8 +540,8 @@ impl<Exe: Executor> ConnectionSender<Exe> {
538540
cumulative: bool,
539541
) -> Result<(), ConnectionError> {
540542
self.tx
541-
.unbounded_send(messages::ack(consumer_id, message_ids, cumulative))
542-
.map_err(|_| ConnectionError::Disconnected)
543+
.try_send(messages::ack(consumer_id, message_ids, cumulative))?;
544+
Ok(())
543545
}
544546

545547
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
@@ -549,11 +551,11 @@ impl<Exe: Executor> ConnectionSender<Exe> {
549551
message_ids: Vec<proto::MessageIdData>,
550552
) -> Result<(), ConnectionError> {
551553
self.tx
552-
.unbounded_send(messages::redeliver_unacknowleged_messages(
554+
.try_send(messages::redeliver_unacknowleged_messages(
553555
consumer_id,
554556
message_ids,
555-
))
556-
.map_err(|_| ConnectionError::Disconnected)
557+
))?;
558+
Ok(())
557559
}
558560

559561
#[cfg_attr(feature = "telemetry", tracing::instrument(skip_all))]
@@ -661,7 +663,7 @@ impl<Exe: Executor> ConnectionSender<Exe> {
661663
match (
662664
self.registrations
663665
.unbounded_send(Register::Request { key, resolver }),
664-
self.tx.unbounded_send(msg),
666+
self.tx.try_send(msg),
665667
) {
666668
(Ok(_), Ok(_)) => {
667669
let connection_id = self.connection_id;
@@ -700,6 +702,7 @@ impl<Exe: Executor> ConnectionSender<Exe> {
700702

701703
Ok(fut)
702704
}
705+
(_, Err(e)) if e.is_full() => Err(ConnectionError::SlowDown),
703706
_ => {
704707
warn!(
705708
"connection {} disconnected sending message to the Pulsar server",
@@ -781,6 +784,7 @@ impl<Exe: Executor> Connection<Exe> {
781784
tls_hostname_verification_enabled: bool,
782785
connection_timeout: Duration,
783786
operation_timeout: Duration,
787+
outbound_channel_size: usize,
784788
executor: Arc<Exe>,
785789
) -> Result<Connection<Exe>, ConnectionError> {
786790
if url.scheme() != "pulsar" && url.scheme() != "pulsar+ssl" {
@@ -839,6 +843,7 @@ impl<Exe: Executor> Connection<Exe> {
839843
tls_hostname_verification_enabled,
840844
executor.clone(),
841845
operation_timeout,
846+
outbound_channel_size,
842847
);
843848
let delay_f = executor.delay(connection_timeout);
844849

@@ -916,6 +921,7 @@ impl<Exe: Executor> Connection<Exe> {
916921
tls_hostname_verification_enabled: bool,
917922
executor: Arc<Exe>,
918923
operation_timeout: Duration,
924+
outbound_channel_size: usize,
919925
) -> Result<ConnectionSender<Exe>, ConnectionError> {
920926
match executor.kind() {
921927
#[cfg(feature = "tokio-runtime")]
@@ -945,6 +951,7 @@ impl<Exe: Executor> Connection<Exe> {
945951
proxy_to_broker_url,
946952
executor,
947953
operation_timeout,
954+
outbound_channel_size,
948955
)
949956
.await
950957
} else {
@@ -959,6 +966,7 @@ impl<Exe: Executor> Connection<Exe> {
959966
proxy_to_broker_url,
960967
executor,
961968
operation_timeout,
969+
outbound_channel_size,
962970
)
963971
.await
964972
}
@@ -1007,6 +1015,7 @@ impl<Exe: Executor> Connection<Exe> {
10071015
proxy_to_broker_url,
10081016
executor,
10091017
operation_timeout,
1018+
outbound_channel_size,
10101019
)
10111020
.await
10121021
} else {
@@ -1021,6 +1030,7 @@ impl<Exe: Executor> Connection<Exe> {
10211030
proxy_to_broker_url,
10221031
executor,
10231032
operation_timeout,
1033+
outbound_channel_size,
10241034
)
10251035
.await
10261036
}
@@ -1053,6 +1063,7 @@ impl<Exe: Executor> Connection<Exe> {
10531063
proxy_to_broker_url,
10541064
executor,
10551065
operation_timeout,
1066+
outbound_channel_size,
10561067
)
10571068
.await
10581069
} else {
@@ -1067,6 +1078,7 @@ impl<Exe: Executor> Connection<Exe> {
10671078
proxy_to_broker_url,
10681079
executor,
10691080
operation_timeout,
1081+
outbound_channel_size,
10701082
)
10711083
.await
10721084
}
@@ -1119,6 +1131,7 @@ impl<Exe: Executor> Connection<Exe> {
11191131
proxy_to_broker_url,
11201132
executor,
11211133
operation_timeout,
1134+
outbound_channel_size,
11221135
)
11231136
.await
11241137
} else {
@@ -1133,6 +1146,7 @@ impl<Exe: Executor> Connection<Exe> {
11331146
proxy_to_broker_url,
11341147
executor,
11351148
operation_timeout,
1149+
outbound_channel_size,
11361150
)
11371151
.await
11381152
}
@@ -1155,6 +1169,7 @@ impl<Exe: Executor> Connection<Exe> {
11551169
proxy_to_broker_url: Option<String>,
11561170
executor: Arc<Exe>,
11571171
operation_timeout: Duration,
1172+
outbound_channel_size: usize,
11581173
) -> Result<ConnectionSender<Exe>, ConnectionError>
11591174
where
11601175
S: Stream<Item = Result<Message, ConnectionError>>,
@@ -1194,7 +1209,7 @@ impl<Exe: Executor> Connection<Exe> {
11941209
}?;
11951210

11961211
let (mut sink, stream) = stream.split();
1197-
let (tx, mut rx) = mpsc::unbounded();
1212+
let (tx, rx) = async_channel::bounded(outbound_channel_size);
11981213
let (registrations_tx, registrations_rx) = mpsc::unbounded();
11991214
let error = SharedError::new();
12001215
let (receiver_shutdown_tx, receiver_shutdown_rx) = oneshot::channel();
@@ -1220,7 +1235,7 @@ impl<Exe: Executor> Connection<Exe> {
12201235

12211236
let err = error.clone();
12221237
let res = executor.spawn(Box::pin(async move {
1223-
while let Some(msg) = rx.next().await {
1238+
while let Ok(msg) = rx.recv().await {
12241239
// println!("real sent msg: {:?}", msg);
12251240
if let Err(e) = sink.send(msg).await {
12261241
err.set(e);
@@ -1236,7 +1251,7 @@ impl<Exe: Executor> Connection<Exe> {
12361251
if auth.is_some() {
12371252
let auth_challenge_res = executor.spawn({
12381253
let err = error.clone();
1239-
let mut tx = tx.clone();
1254+
let tx = tx.clone();
12401255
let auth = auth.clone();
12411256
Box::pin(async move {
12421257
while auth_challenge_rx.next().await.is_some() {
@@ -1796,7 +1811,7 @@ mod tests {
17961811
#[cfg(any(feature = "tokio-runtime", feature = "tokio-rustls-runtime"))]
17971812
async fn receiver_auth_challenge_test() {
17981813
let (message_tx, message_rx) = mpsc::unbounded();
1799-
let (tx, _) = mpsc::unbounded();
1814+
let (tx, _) = async_channel::bounded(10);
18001815
let (_registrations_tx, registrations_rx) = mpsc::unbounded();
18011816
let error = SharedError::new();
18021817
let (_receiver_shutdown_tx, receiver_shutdown_rx) = oneshot::channel();
@@ -1904,6 +1919,7 @@ mod tests {
19041919
None,
19051920
TokioExecutor.into(),
19061921
Duration::from_secs(10),
1922+
100,
19071923
)
19081924
.await;
19091925

src/connection_manager.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ pub struct ConnectionManager<Exe: Executor> {
123123
pub(crate) operation_retry_options: OperationRetryOptions,
124124
tls_options: TlsOptions,
125125
certificate_chain: Vec<Certificate>,
126+
outbound_channel_size: usize,
126127
}
127128

128129
impl<Exe: Executor> ConnectionManager<Exe> {
@@ -133,6 +134,7 @@ impl<Exe: Executor> ConnectionManager<Exe> {
133134
connection_retry: Option<ConnectionRetryOptions>,
134135
operation_retry_options: OperationRetryOptions,
135136
tls: Option<TlsOptions>,
137+
outbound_channel_size: usize,
136138
executor: Arc<Exe>,
137139
) -> Result<Self, ConnectionError> {
138140
let connection_retry_options = connection_retry.unwrap_or_default();
@@ -191,6 +193,7 @@ impl<Exe: Executor> ConnectionManager<Exe> {
191193
operation_retry_options,
192194
tls_options,
193195
certificate_chain,
196+
outbound_channel_size,
194197
};
195198
let broker_address = BrokerAddress {
196199
url: url.clone(),
@@ -312,6 +315,7 @@ impl<Exe: Executor> ConnectionManager<Exe> {
312315
self.tls_options.tls_hostname_verification_enabled,
313316
self.connection_retry_options.connection_timeout,
314317
self.operation_retry_options.operation_timeout,
318+
self.outbound_channel_size,
315319
self.executor.clone(),
316320
)
317321
.await

src/consumer/engine.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,11 @@ impl<Exe: Executor> ConsumerEngine<Exe> {
159159
.sender()
160160
.send_flow(self.id, self.batch_size - self.remaining_messages)?;
161161
}
162+
Err(ConnectionError::SlowDown) => {
163+
self.connection
164+
.sender()
165+
.send_flow(self.id, self.batch_size - self.remaining_messages)?;
166+
}
162167
Err(e) => return Err(e.into()),
163168
}
164169
self.remaining_messages = self.batch_size;

0 commit comments

Comments
 (0)