1use crate::utils::AsyncJoinOnDrop;
18use anyhow::anyhow;
19use async_nats::{
20 Client, ConnectOptions, HeaderMap, HeaderValue, Message, PublishError, RequestError,
21 RequestErrorKind, Subject, SubscribeError, Subscriber, ToServerAddrs,
22};
23use backon::{BackoffBuilder, ExponentialBuilder};
24use futures::channel::mpsc;
25use futures::stream::FuturesUnordered;
26use futures::{FutureExt, Stream, StreamExt, select};
27use parity_scale_codec::{Decode, Encode};
28use std::any::type_name;
29use std::collections::VecDeque;
30use std::fmt;
31use std::future::Future;
32use std::marker::PhantomData;
33use std::ops::Deref;
34use std::pin::Pin;
35use std::sync::Arc;
36use std::task::{Context, Poll};
37use std::time::Duration;
38use thiserror::Error;
39use tracing::{Instrument, debug, error, trace, warn};
40use ulid::Ulid;
41
42const EXPECTED_MESSAGE_SIZE: usize = 2 * 1024 * 1024;
43const ACKNOWLEDGEMENT_TIMEOUT: Duration = Duration::from_mins(1);
44const REQUEST_TIMEOUT: Duration = Duration::from_mins(5);
47
48pub trait GenericRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
54 const SUBJECT: &'static str;
56 type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
58}
59
60pub trait GenericStreamRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
67 const SUBJECT: &'static str;
69 type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
75}
76
77#[derive(Debug, Encode, Decode)]
81enum GenericStreamResponses<Response> {
82 Continue {
84 index: u32,
86 responses: VecDeque<Response>,
88 ack_subject: String,
91 },
92 Last {
94 index: u32,
96 responses: VecDeque<Response>,
98 },
99}
100
101impl<Response> From<GenericStreamResponses<Response>> for VecDeque<Response> {
102 #[inline]
103 fn from(value: GenericStreamResponses<Response>) -> Self {
104 #[expect(
105 clippy::rest_pattern_accessible_field,
106 reason = "Do not need other fields"
107 )]
108 match value {
109 GenericStreamResponses::Continue { responses, .. } => responses,
110 GenericStreamResponses::Last { responses, .. } => responses,
111 }
112 }
113}
114
115impl<Response> GenericStreamResponses<Response> {
116 fn next(&mut self) -> Option<Response> {
117 #[expect(
118 clippy::rest_pattern_accessible_field,
119 reason = "Do not need other fields"
120 )]
121 match self {
122 GenericStreamResponses::Continue { responses, .. } => responses.pop_front(),
123 GenericStreamResponses::Last { responses, .. } => responses.pop_front(),
124 }
125 }
126
127 fn index(&self) -> u32 {
128 #[expect(
129 clippy::rest_pattern_accessible_field,
130 reason = "Do not need other fields"
131 )]
132 match self {
133 GenericStreamResponses::Continue { index, .. } => *index,
134 GenericStreamResponses::Last { index, .. } => *index,
135 }
136 }
137
138 fn ack_subject(&self) -> Option<&str> {
139 #[expect(
140 clippy::rest_pattern_accessible_field,
141 reason = "Do not need other fields"
142 )]
143 if let GenericStreamResponses::Continue { ack_subject, .. } = self {
144 Some(ack_subject)
145 } else {
146 None
147 }
148 }
149
150 #[expect(
151 clippy::rest_pattern_accessible_field,
152 reason = "Do not care about fields"
153 )]
154 fn is_last(&self) -> bool {
155 matches!(self, Self::Last { .. })
156 }
157}
158
159#[derive(Debug, Error)]
161pub enum StreamRequestError {
162 #[error("Subscribe error: {0}")]
164 Subscribe(#[from] SubscribeError),
165 #[error("Publish error: {0}")]
167 Publish(#[from] PublishError),
168}
169
170#[derive(Debug)]
173#[pin_project::pin_project]
174pub struct StreamResponseSubscriber<Response> {
175 #[pin]
176 subscriber: Subscriber,
177 response_subject: String,
178 buffered_responses: Option<GenericStreamResponses<Response>>,
179 next_index: u32,
180 acknowledgement_sender: mpsc::UnboundedSender<(String, u32)>,
181 _background_task: AsyncJoinOnDrop<()>,
182 _phantom: PhantomData<Response>,
183}
184
185impl<Response> Stream for StreamResponseSubscriber<Response>
186where
187 Response: Decode,
188{
189 type Item = Response;
190
191 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
192 if let Some(buffered_responses) = self.buffered_responses.as_mut() {
193 if let Some(response) = buffered_responses.next() {
194 return Poll::Ready(Some(response));
195 } else if buffered_responses.is_last() {
196 return Poll::Ready(None);
197 }
198
199 self.buffered_responses.take();
200 self.next_index += 1;
201 }
202
203 let mut projected = self.project();
204 match projected.subscriber.poll_next_unpin(cx) {
205 Poll::Ready(Some(message)) => {
206 match GenericStreamResponses::<Response>::decode(&mut message.payload.as_ref()) {
207 Ok(mut responses) => {
208 if responses.index() != *projected.next_index {
209 warn!(
210 actual_index = %responses.index(),
211 expected_index = %*projected.next_index,
212 message_type = %type_name::<Response>(),
213 response_subject = %projected.response_subject,
214 "Received unexpected response stream index, aborting stream"
215 );
216
217 return Poll::Ready(None);
218 }
219
220 if let Some(ack_subject) = responses.ack_subject() {
221 let index = responses.index();
222 let ack_subject = ack_subject.to_string();
223
224 if let Err(error) = projected
225 .acknowledgement_sender
226 .unbounded_send((ack_subject.clone(), index))
227 {
228 warn!(
229 %error,
230 %index,
231 message_type = %type_name::<Response>(),
232 response_subject = %projected.response_subject,
233 %ack_subject,
234 "Failed to send acknowledgement for stream response"
235 );
236 }
237 }
238
239 if let Some(response) = responses.next() {
240 *projected.buffered_responses = Some(responses);
241 Poll::Ready(Some(response))
242 } else {
243 Poll::Ready(None)
244 }
245 }
246 Err(error) => {
247 warn!(
248 %error,
249 response_type = %type_name::<Response>(),
250 response_subject = %projected.response_subject,
251 message = %hex::encode(message.payload),
252 "Failed to decode stream response"
253 );
254
255 Poll::Ready(None)
256 }
257 }
258 }
259 Poll::Ready(None) => Poll::Ready(None),
260 Poll::Pending => Poll::Pending,
261 }
262 }
263}
264
265impl<Response> StreamResponseSubscriber<Response> {
266 fn new(subscriber: Subscriber, response_subject: String, nats_client: NatsClient) -> Self {
267 let (acknowledgement_sender, mut acknowledgement_receiver) =
268 mpsc::unbounded::<(String, u32)>();
269
270 let ack_publisher_fut = {
271 let response_subject = response_subject.clone();
272
273 async move {
274 while let Some((subject, index)) = acknowledgement_receiver.next().await {
275 trace!(
276 %subject,
277 %index,
278 %response_subject,
279 %index,
280 "Sending stream response acknowledgement"
281 );
282 if let Err(error) = nats_client
283 .publish(subject.clone(), index.to_le_bytes().to_vec().into())
284 .await
285 {
286 warn!(
287 %error,
288 %subject,
289 %index,
290 %response_subject,
291 %index,
292 "Failed to send stream response acknowledgement"
293 );
294 return;
295 }
296 }
297 }
298 };
299 let background_task =
300 AsyncJoinOnDrop::new(tokio::spawn(ack_publisher_fut.in_current_span()), true);
301
302 Self {
303 response_subject,
304 subscriber,
305 buffered_responses: None,
306 next_index: 0,
307 acknowledgement_sender,
308 _background_task: background_task,
309 _phantom: PhantomData,
310 }
311 }
312}
313
314pub trait GenericNotification: Encode + Decode + fmt::Debug + Send + Sync + 'static {
316 const SUBJECT: &'static str;
319}
320
321pub trait GenericBroadcast: Encode + Decode + fmt::Debug + Send + Sync + 'static {
327 const SUBJECT: &'static str;
329
330 fn deterministic_message_id(&self) -> Option<HeaderValue> {
333 None
334 }
335}
336
337#[derive(Debug)]
339#[pin_project::pin_project]
340pub struct SubscriberWrapper<Message> {
341 #[pin]
342 subscriber: Subscriber,
343 _phantom: PhantomData<Message>,
344}
345
346impl<Message> Stream for SubscriberWrapper<Message>
347where
348 Message: Decode,
349{
350 type Item = Message;
351
352 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
353 match self.project().subscriber.poll_next_unpin(cx) {
354 Poll::Ready(Some(message)) => match Message::decode(&mut message.payload.as_ref()) {
355 Ok(message) => Poll::Ready(Some(message)),
356 Err(error) => {
357 warn!(
358 %error,
359 message_type = %type_name::<Message>(),
360 message = %hex::encode(message.payload),
361 "Failed to decode stream message"
362 );
363
364 Poll::Pending
365 }
366 },
367 Poll::Ready(None) => Poll::Ready(None),
368 Poll::Pending => Poll::Pending,
369 }
370 }
371}
372
373#[derive(Debug)]
374struct Inner {
375 client: Client,
376 request_retry_backoff_policy: ExponentialBuilder,
377 approximate_max_message_size: usize,
378 max_message_size: usize,
379}
380
381#[derive(Debug, Clone)]
383pub struct NatsClient {
384 inner: Arc<Inner>,
385}
386
387impl Deref for NatsClient {
388 type Target = Client;
389
390 #[inline]
391 fn deref(&self) -> &Self::Target {
392 &self.inner.client
393 }
394}
395
396impl NatsClient {
397 pub async fn new<A>(
399 addrs: A,
400 request_retry_backoff_policy: ExponentialBuilder,
401 ) -> Result<Self, async_nats::Error>
402 where
403 A: ToServerAddrs,
404 {
405 let servers = addrs.to_server_addrs()?.collect::<Vec<_>>();
406 Self::from_client(
407 async_nats::connect_with_options(
408 &servers,
409 ConnectOptions::default().request_timeout(Some(REQUEST_TIMEOUT)),
410 )
411 .await?,
412 request_retry_backoff_policy,
413 )
414 }
415
416 pub fn from_client(
418 client: Client,
419 request_retry_backoff_policy: ExponentialBuilder,
420 ) -> Result<Self, async_nats::Error> {
421 let max_payload = client.server_info().max_payload;
422 if max_payload < EXPECTED_MESSAGE_SIZE {
423 return Err(format!(
424 "Max payload {max_payload} is smaller than expected {EXPECTED_MESSAGE_SIZE}, \
425 increase it by specifying max_payload = 2MB or higher number in NATS configuration"
426 )
427 .into());
428 }
429
430 let inner = Inner {
431 client,
432 request_retry_backoff_policy,
433 approximate_max_message_size: max_payload * 9 / 10,
435 max_message_size: max_payload,
437 };
438
439 Ok(Self {
440 inner: Arc::new(inner),
441 })
442 }
443
444 pub fn approximate_max_message_size(&self) -> usize {
447 self.inner.approximate_max_message_size
448 }
449
450 pub async fn request<Request>(
452 &self,
453 request: &Request,
454 instance: Option<&str>,
455 ) -> Result<Request::Response, RequestError>
456 where
457 Request: GenericRequest,
458 {
459 let subject = subject_with_instance(Request::SUBJECT, instance);
460 let mut maybe_retry_backoff = None;
461 let message = loop {
462 match self
463 .inner
464 .client
465 .request(subject.clone(), request.encode().into())
466 .await
467 {
468 Ok(message) => {
469 break message;
470 }
471 Err(error) => {
472 match error.kind() {
473 RequestErrorKind::TimedOut | RequestErrorKind::NoResponders => {
474 }
476 RequestErrorKind::InvalidSubject
477 | RequestErrorKind::MaxPayloadExceeded
478 | RequestErrorKind::Other => {
479 return Err(error);
480 }
481 }
482
483 let retry_backoff = maybe_retry_backoff
484 .get_or_insert_with(|| self.inner.request_retry_backoff_policy.build());
485
486 if let Some(delay) = retry_backoff.next() {
487 debug!(
488 %subject,
489 %error,
490 request_type = %type_name::<Request>(),
491 ?delay,
492 "Failed to make request, retrying after some delay"
493 );
494
495 tokio::time::sleep(delay).await;
496 } else {
497 return Err(error);
498 }
499 }
500 }
501 };
502
503 let response =
504 Request::Response::decode(&mut message.payload.as_ref()).map_err(|error| {
505 warn!(
506 %subject,
507 %error,
508 response_type = %type_name::<Request::Response>(),
509 response = %hex::encode(message.payload),
510 "Response decoding failed"
511 );
512
513 RequestErrorKind::Other
514 })?;
515
516 Ok(response)
517 }
518
519 pub async fn request_responder<Request, F, OP>(
534 &self,
535 instance: Option<&str>,
536 queue_group: Option<String>,
537 process: OP,
538 ) -> anyhow::Result<()>
539 where
540 Request: GenericRequest,
541 F: Future<Output = Option<Request::Response>> + Send,
542 OP: Fn(Request) -> F + Send + Sync,
543 {
544 let mut processing = FuturesUnordered::new();
546
547 let subscription = self
548 .common_subscribe(Request::SUBJECT, instance, queue_group)
549 .await
550 .map_err(|error| {
551 anyhow!(
552 "Failed to subscribe to {} requests for {instance:?}: {error}",
553 type_name::<Request>(),
554 )
555 })?;
556
557 debug!(
558 request_type = %type_name::<Request>(),
559 ?subscription,
560 "Requests subscription"
561 );
562 let mut subscription = subscription.fuse();
563
564 loop {
565 select! {
566 message = subscription.select_next_some() => {
567 processing.push(
569 self
570 .process_request(
571 message,
572 &process,
573 )
574 .in_current_span(),
575 );
576 },
577 _ = processing.next() => {
578 },
580 complete => {
581 break;
582 }
583 }
584 }
585
586 Ok(())
587 }
588
589 async fn process_request<Request, F, OP>(&self, message: Message, process: OP)
590 where
591 Request: GenericRequest,
592 F: Future<Output = Option<Request::Response>> + Send,
593 OP: Fn(Request) -> F + Send + Sync,
594 {
595 let Some(reply_subject) = message.reply else {
596 return;
597 };
598
599 let message_payload_size = message.payload.len();
600 let request = match Request::decode(&mut message.payload.as_ref()) {
601 Ok(request) => {
602 drop(message.payload);
604 request
605 }
606 Err(error) => {
607 warn!(
608 request_type = %type_name::<Request>(),
609 %error,
610 message = %hex::encode(message.payload),
611 "Failed to decode request"
612 );
613 return;
614 }
615 };
616
617 if message_payload_size > 1024 {
619 trace!(
620 request_type = %type_name::<Request>(),
621 %reply_subject,
622 "Processing request"
623 );
624 } else {
625 trace!(
626 request_type = %type_name::<Request>(),
627 ?request,
628 %reply_subject,
629 "Processing request"
630 );
631 }
632
633 if let Some(response) = process(request).await
634 && let Err(error) = self.publish(reply_subject, response.encode().into()).await
635 {
636 warn!(
637 request_type = %type_name::<Request>(),
638 %error,
639 "Failed to send response"
640 );
641 }
642 }
643
644 pub async fn stream_request<Request>(
646 &self,
647 request: &Request,
648 instance: Option<&str>,
649 ) -> Result<StreamResponseSubscriber<Request::Response>, StreamRequestError>
650 where
651 Request: GenericStreamRequest,
652 {
653 let stream_request_subject = subject_with_instance(Request::SUBJECT, instance);
654 let stream_response_subject = format!("stream-response.{}", Ulid::generate());
655
656 let subscriber = self
657 .inner
658 .client
659 .subscribe(stream_response_subject.clone())
660 .await?;
661
662 debug!(
663 request_type = %type_name::<Request>(),
664 %stream_request_subject,
665 %stream_response_subject,
666 ?subscriber,
667 "Stream request subscription"
668 );
669
670 self.inner
671 .client
672 .publish_with_reply(
673 stream_request_subject,
674 stream_response_subject.clone(),
675 request.encode().into(),
676 )
677 .await?;
678
679 Ok(StreamResponseSubscriber::new(
680 subscriber,
681 stream_response_subject,
682 self.clone(),
683 ))
684 }
685
686 pub async fn stream_request_responder<Request, F, S, OP>(
701 &self,
702 instance: Option<&str>,
703 queue_group: Option<String>,
704 process: OP,
705 ) -> anyhow::Result<()>
706 where
707 Request: GenericStreamRequest,
708 F: Future<Output = Option<S>> + Send,
709 S: Stream<Item = Request::Response> + Unpin,
710 OP: Fn(Request) -> F + Send + Sync,
711 {
712 let mut processing = FuturesUnordered::new();
714
715 let subscription = self
716 .common_subscribe(Request::SUBJECT, instance, queue_group)
717 .await
718 .map_err(|error| {
719 anyhow!(
720 "Failed to subscribe to {} stream requests for {instance:?}: {error}",
721 type_name::<Request>(),
722 )
723 })?;
724
725 debug!(
726 request_type = %type_name::<Request>(),
727 ?subscription,
728 "Stream requests subscription"
729 );
730 let mut subscription = subscription.fuse();
731
732 loop {
733 select! {
734 message = subscription.select_next_some() => {
735 processing.push(
737 self
738 .process_stream_request(
739 message,
740 &process,
741 )
742 .in_current_span(),
743 );
744 },
745 _ = processing.next() => {
746 },
748 complete => {
749 break;
750 }
751 }
752 }
753
754 Ok(())
755 }
756
757 async fn process_stream_request<Request, F, S, OP>(&self, message: Message, process: OP)
758 where
759 Request: GenericStreamRequest,
760 F: Future<Output = Option<S>> + Send,
761 S: Stream<Item = Request::Response> + Unpin,
762 OP: Fn(Request) -> F + Send + Sync,
763 {
764 let Some(reply_subject) = message.reply else {
765 return;
766 };
767
768 let message_payload_size = message.payload.len();
769 let request = match Request::decode(&mut message.payload.as_ref()) {
770 Ok(request) => {
771 drop(message.payload);
773 request
774 }
775 Err(error) => {
776 warn!(
777 request_type = %type_name::<Request>(),
778 %error,
779 message = %hex::encode(message.payload),
780 "Failed to decode request"
781 );
782 return;
783 }
784 };
785
786 if message_payload_size > 1024 {
788 trace!(
789 request_type = %type_name::<Request>(),
790 %reply_subject,
791 "Processing request"
792 );
793 } else {
794 trace!(
795 request_type = %type_name::<Request>(),
796 ?request,
797 %reply_subject,
798 "Processing request"
799 );
800 }
801
802 if let Some(stream) = process(request).await {
803 self.stream_response::<Request, _>(reply_subject, stream)
804 .await;
805 }
806 }
807
808 async fn stream_response<Request, S>(&self, response_subject: Subject, response_stream: S)
810 where
811 Request: GenericStreamRequest,
812 S: Stream<Item = Request::Response> + Unpin,
813 {
814 type Response<Request> =
815 GenericStreamResponses<<Request as GenericStreamRequest>::Response>;
816
817 let mut response_stream = response_stream.fuse();
818
819 let Some(first_element) = response_stream.next().await else {
821 if let Err(error) = self
822 .publish(
823 response_subject.clone(),
824 Response::<Request>::Last {
825 index: 0,
826 responses: VecDeque::new(),
827 }
828 .encode()
829 .into(),
830 )
831 .await
832 {
833 warn!(
834 %response_subject,
835 %error,
836 request_type = %type_name::<Request>(),
837 response_type = %type_name::<Request::Response>(),
838 "Failed to send stream response"
839 );
840 }
841
842 return;
843 };
844 let max_message_size = self.inner.max_message_size;
845 let approximate_max_message_size = self.approximate_max_message_size();
846 let max_responses_per_message = approximate_max_message_size / first_element.encoded_size();
847
848 let ack_subject = format!("stream-response-ack.{}", Ulid::generate());
849 let mut ack_subscription = match self.subscribe(ack_subject.clone()).await {
850 Ok(ack_subscription) => ack_subscription,
851 Err(error) => {
852 warn!(
853 %response_subject,
854 %error,
855 request_type = %type_name::<Request>(),
856 response_type = %type_name::<Request::Response>(),
857 "Failed to subscribe to ack subject"
858 );
859 return;
860 }
861 };
862 debug!(
863 %response_subject,
864 request_type = %type_name::<Request>(),
865 response_type = %type_name::<Request::Response>(),
866 ?ack_subscription,
867 "Ack subscription subscription"
868 );
869 let mut index = 0;
870 let mut buffer = VecDeque::with_capacity(max_responses_per_message);
872 buffer.push_back(first_element);
873 let mut overflow_buffer = VecDeque::new();
874
875 loop {
876 if buffer.is_empty()
878 && let Some(element) = response_stream.next().await
879 {
880 buffer.push_back(element);
881 }
882 while buffer.encoded_size() < approximate_max_message_size
883 && let Some(element) = response_stream.next().now_or_never().flatten()
884 {
885 buffer.push_back(element);
886 }
887
888 loop {
889 let is_done = response_stream.is_done() && overflow_buffer.is_empty();
890 let num_messages = buffer.len();
891 let response = if is_done {
892 Response::<Request>::Last {
893 index,
894 responses: buffer,
895 }
896 } else {
897 Response::<Request>::Continue {
898 index,
899 responses: buffer,
900 ack_subject: ack_subject.clone(),
901 }
902 };
903 let encoded_response = response.encode();
904 let encoded_response_len = encoded_response.len();
905 if encoded_response_len > max_message_size {
908 buffer = response.into();
909 if let Some(element) = buffer.pop_back() {
910 if buffer.is_empty() {
911 error!(
912 ?element,
913 encoded_response_len,
914 max_message_size,
915 "Element was too large to fit into NATS message, this is an \
916 implementation bug"
917 );
918 }
919 overflow_buffer.push_front(element);
920 continue;
921 }
922
923 error!(
924 %response_subject,
925 request_type = %type_name::<Request>(),
926 response_type = %type_name::<Request::Response>(),
927 "Empty response overflown message size, this should never happen"
928 );
929 return;
930 }
931
932 debug!(
933 %response_subject,
934 num_messages,
935 %index,
936 %is_done,
937 "Publishing stream response messages",
938 );
939
940 if let Err(error) = self
941 .publish(response_subject.clone(), encoded_response.into())
942 .await
943 {
944 warn!(
945 %response_subject,
946 %error,
947 request_type = %type_name::<Request>(),
948 response_type = %type_name::<Request::Response>(),
949 "Failed to send stream response"
950 );
951 return;
952 }
953
954 if is_done {
955 return;
956 }
957
958 buffer = response.into();
959 buffer.clear();
960 buffer.extend(overflow_buffer.drain(..));
962
963 if index >= 1 {
964 let expected_index = index - 1;
966
967 trace!(
968 %response_subject,
969 %expected_index,
970 "Waiting for acknowledgement"
971 );
972 match tokio::time::timeout(ACKNOWLEDGEMENT_TIMEOUT, ack_subscription.next())
973 .await
974 {
975 Ok(Some(message)) => {
976 if let Some(received_index) =
977 message.payload.get(..size_of::<u32>()).map(|bytes| {
978 u32::from_le_bytes(
979 bytes.try_into().expect("Correctly chunked slice; qed"),
980 )
981 })
982 {
983 debug!(
984 %response_subject,
985 %received_index,
986 "Received acknowledgement"
987 );
988 if received_index != expected_index {
989 warn!(
990 %response_subject,
991 %received_index,
992 %expected_index,
993 request_type = %type_name::<Request>(),
994 response_type = %type_name::<Request::Response>(),
995 message = %hex::encode(message.payload),
996 "Unexpected acknowledgement index"
997 );
998 return;
999 }
1000 } else {
1001 warn!(
1002 %response_subject,
1003 request_type = %type_name::<Request>(),
1004 response_type = %type_name::<Request::Response>(),
1005 message = %hex::encode(message.payload),
1006 "Unexpected acknowledgement message"
1007 );
1008 return;
1009 }
1010 }
1011 Ok(None) => {
1012 warn!(
1013 %response_subject,
1014 request_type = %type_name::<Request>(),
1015 response_type = %type_name::<Request::Response>(),
1016 "Acknowledgement stream ended unexpectedly"
1017 );
1018 return;
1019 }
1020 Err(_error) => {
1021 warn!(
1022 %response_subject,
1023 %expected_index,
1024 request_type = %type_name::<Request>(),
1025 response_type = %type_name::<Request::Response>(),
1026 "Acknowledgement wait timed out"
1027 );
1028 return;
1029 }
1030 }
1031 }
1032
1033 index += 1;
1034
1035 if buffer.is_empty() {
1037 break;
1038 }
1039 }
1040 }
1041 }
1042
1043 pub async fn notification<Notification>(
1045 &self,
1046 notification: &Notification,
1047 instance: Option<&str>,
1048 ) -> Result<(), PublishError>
1049 where
1050 Notification: GenericNotification,
1051 {
1052 self.inner
1053 .client
1054 .publish(
1055 subject_with_instance(Notification::SUBJECT, instance),
1056 notification.encode().into(),
1057 )
1058 .await
1059 }
1060
1061 pub async fn broadcast<Broadcast>(
1063 &self,
1064 message: &Broadcast,
1065 instance: &str,
1066 ) -> Result<(), PublishError>
1067 where
1068 Broadcast: GenericBroadcast,
1069 {
1070 self.inner
1071 .client
1072 .publish_with_headers(
1073 Broadcast::SUBJECT.replace('*', instance),
1074 {
1075 let mut headers = HeaderMap::new();
1076 if let Some(message_id) = message.deterministic_message_id() {
1077 headers.insert("Nats-Msg-Id", message_id);
1078 }
1079 headers
1080 },
1081 message.encode().into(),
1082 )
1083 .await
1084 }
1085
1086 pub async fn subscribe_to_notifications<Notification>(
1089 &self,
1090 instance: Option<&str>,
1091 queue_group: Option<String>,
1092 ) -> Result<SubscriberWrapper<Notification>, SubscribeError>
1093 where
1094 Notification: GenericNotification,
1095 {
1096 self.simple_subscribe(Notification::SUBJECT, instance, queue_group)
1097 .await
1098 }
1099
1100 pub async fn subscribe_to_broadcasts<Broadcast>(
1103 &self,
1104 instance: Option<&str>,
1105 queue_group: Option<String>,
1106 ) -> Result<SubscriberWrapper<Broadcast>, SubscribeError>
1107 where
1108 Broadcast: GenericBroadcast,
1109 {
1110 self.simple_subscribe(Broadcast::SUBJECT, instance, queue_group)
1111 .await
1112 }
1113
1114 async fn simple_subscribe<Message>(
1117 &self,
1118 subject: &'static str,
1119 instance: Option<&str>,
1120 queue_group: Option<String>,
1121 ) -> Result<SubscriberWrapper<Message>, SubscribeError>
1122 where
1123 Message: Decode,
1124 {
1125 let subscriber = self
1126 .common_subscribe(subject, instance, queue_group)
1127 .await?;
1128 debug!(
1129 %subject,
1130 message_type = %type_name::<Message>(),
1131 ?subscriber,
1132 "Simple subscription"
1133 );
1134
1135 Ok(SubscriberWrapper {
1136 subscriber,
1137 _phantom: PhantomData,
1138 })
1139 }
1140
1141 async fn common_subscribe(
1144 &self,
1145 subject: &'static str,
1146 instance: Option<&str>,
1147 queue_group: Option<String>,
1148 ) -> Result<Subscriber, SubscribeError> {
1149 let subscriber = if let Some(queue_group) = queue_group {
1150 self.inner
1151 .client
1152 .queue_subscribe(subject_with_instance(subject, instance), queue_group)
1153 .await?
1154 } else {
1155 self.inner
1156 .client
1157 .subscribe(subject_with_instance(subject, instance))
1158 .await?
1159 };
1160
1161 Ok(subscriber)
1162 }
1163}
1164
1165fn subject_with_instance(subject: &'static str, instance: Option<&str>) -> Subject {
1166 if let Some(instance) = instance {
1167 Subject::from(subject.replace('*', instance))
1168 } else {
1169 Subject::from_static(subject)
1170 }
1171}