Skip to main content

ab_farmer/cluster/
nats_client.rs

1//! NATS client
2//!
3//! [`NatsClient`] provided here is a wrapper around [`Client`] that provides convenient methods
4//! using domain-specific traits.
5//!
6//! Before reading code, make sure to familiarize yourself with NATS documentation, especially with
7//! [subjects](https://docs.nats.io/nats-concepts/subjects) and
8//! [Core NATS](https://docs.nats.io/nats-concepts/core-nats) features.
9//!
10//! Abstractions provided here cover a few use cases:
11//! * request/response (for example piece request)
12//! * request/stream of responses (for example a stream of plotted sectors of the farmer)
13//! * notifications (typically targeting a particular instance of an app) and corresponding
14//!   subscriptions (for example solution notification)
15//! * broadcasts and corresponding subscriptions (for example slot info broadcast)
16
17use 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);
44/// Requests should time out eventually, but we should set a larger timeout to allow for spikes in
45/// load to be absorbed gracefully
46const REQUEST_TIMEOUT: Duration = Duration::from_mins(5);
47
48/// Generic request with associated response.
49///
50/// Used for cases where request/response pattern is needed and response contains a single small
51/// message. For large messages or multiple messages chunking with [`GenericStreamRequest`] can be
52/// used instead.
53pub trait GenericRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
54    /// Request subject with optional `*` in place of application instance to receive the request
55    const SUBJECT: &'static str;
56    /// Response type that corresponds to this request
57    type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
58}
59
60/// Generic stream request where response is streamed using
61/// [`NatsClient::stream_request_responder`].
62///
63/// Used for cases where a large payload that doesn't fit into NATS message needs to be sent or
64/// there is a very large number of messages to send. For simple request/response patten
65/// [`GenericRequest`] can be used instead.
66pub trait GenericStreamRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
67    /// Request subject with optional `*` in place of application instance to receive the request
68    const SUBJECT: &'static str;
69    /// Response type that corresponds to this stream request.
70    ///
71    /// These responses are send as a stream of messages, each message must fit into NATS message,
72    /// [`NatsClient::approximate_max_message_size()`] can be used to estimate appropriate message
73    /// size in case chunking is needed.
74    type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
75}
76
77/// Messages sent in response to [`GenericStreamRequest`].
78///
79/// Empty list of responses means the end of the stream.
80#[derive(Debug, Encode, Decode)]
81enum GenericStreamResponses<Response> {
82    /// Some responses, but the stream didn't end yet
83    Continue {
84        /// Monotonically increasing index of responses in a stream
85        index: u32,
86        /// Individual responses
87        responses: VecDeque<Response>,
88        /// Subject where to send acknowledgement of received stream response indices, which acts
89        /// as a backpressure mechanism
90        ack_subject: String,
91    },
92    /// Remaining responses and this is the end of the stream.
93    Last {
94        /// Monotonically increasing index of responses in a stream
95        index: u32,
96        /// Individual responses
97        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/// Stream request error
160#[derive(Debug, Error)]
161pub enum StreamRequestError {
162    /// Subscribe error
163    #[error("Subscribe error: {0}")]
164    Subscribe(#[from] SubscribeError),
165    /// Publish error
166    #[error("Publish error: {0}")]
167    Publish(#[from] PublishError),
168}
169
170/// Wrapper around subscription that transforms stream of wrapped response messages into a normal
171/// `Response` stream.
172#[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
314/// Generic one-off notification
315pub trait GenericNotification: Encode + Decode + fmt::Debug + Send + Sync + 'static {
316    /// Notification subject with optional `*` in place of application instance receiving the
317    /// request
318    const SUBJECT: &'static str;
319}
320
321/// Generic broadcast message.
322///
323/// Broadcast messages are sent by an instance to (potentially) an instance-specific subject that
324/// any other app can subscribe to. The same broadcast message can also originate from multiple
325/// places and be de-duplicated using [`Self::deterministic_message_id`].
326pub trait GenericBroadcast: Encode + Decode + fmt::Debug + Send + Sync + 'static {
327    /// Broadcast subject with optional `*` in place of application instance sending broadcast
328    const SUBJECT: &'static str;
329
330    /// Deterministic message ID that is used for de-duplicating messages broadcast by different
331    /// instances
332    fn deterministic_message_id(&self) -> Option<HeaderValue> {
333        None
334    }
335}
336
337/// Subscriber wrapper that decodes messages automatically and skips messages that can't be decoded
338#[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/// NATS client wrapper that can be used to interact with other cluster-specific clients
382#[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    /// Create a new instance by connecting to specified addresses
398    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    /// Create new client from existing NATS instance
417    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            // Allow up to 90%, the rest will be wrapper data structures, etc.
434            approximate_max_message_size: max_payload * 9 / 10,
435            // Allow up to 90%, the rest will be wrapper data structures, etc.
436            max_message_size: max_payload,
437        };
438
439        Ok(Self {
440            inner: Arc::new(inner),
441        })
442    }
443
444    /// Approximate max message size (a few more bytes will not hurt), the actual limit is expected
445    /// to be a bit higher
446    pub fn approximate_max_message_size(&self) -> usize {
447        self.inner.approximate_max_message_size
448    }
449
450    /// Make request and wait for response
451    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                            // Continue with retries
475                        }
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    /// Responds to requests from the given subject using the provided processing function.
520    ///
521    /// This will create a subscription on the subject for the given instance (if provided) and
522    /// queue group. Incoming messages will be deserialized as the request type `Request` and passed
523    /// to the `process` function to produce a response of type `Request::Response`. The response
524    /// will then be sent back on the reply subject from the original request.
525    ///
526    /// Each request is processed in a newly created async tokio task.
527    ///
528    /// # Arguments
529    ///
530    /// * `instance` - Optional instance name to use in place of the `*` in the subject
531    /// * `group` - The queue group name for the subscription
532    /// * `process` - The function to call with the decoded request to produce a response
533    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        // Initialize with pending future so it never ends
545        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                    // Create background task for concurrent processing
568                    processing.push(
569                        self
570                            .process_request(
571                                message,
572                                &process,
573                            )
574                            .in_current_span(),
575                    );
576                },
577                _ = processing.next() => {
578                    // Nothing to do here
579                },
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                // Free allocation early
603                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        // Avoid printing large messages in logs
618        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    /// Make request that expects stream response
645    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    /// Responds to stream requests from the given subject using the provided processing function.
687    ///
688    /// This will create a subscription on the subject for the given instance (if provided) and
689    /// queue group. Incoming messages will be deserialized as the request type `Request` and passed
690    /// to the `process` function to produce a stream response of type `Request::Response`. The
691    /// stream response will then be sent back on the reply subject from the original request.
692    ///
693    /// Each request is processed in a newly created async tokio task.
694    ///
695    /// # Arguments
696    ///
697    /// * `instance` - Optional instance name to use in place of the `*` in the subject
698    /// * `group` - The queue group name for the subscription
699    /// * `process` - The function to call with the decoded request to produce a response
700    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        // Initialize with pending future so it never ends
713        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                    // Create background task for concurrent processing
736                    processing.push(
737                        self
738                        .process_stream_request(
739                            message,
740                            &process,
741                        )
742                        .in_current_span(),
743                    );
744                },
745                _ = processing.next() => {
746                    // Nothing to do here
747                },
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                // Free allocation early
772                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        // Avoid printing large messages in logs
787        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    /// Helper method to send responses to requests initiated with [`Self::stream_request`]
809    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        // Pull the first element to measure response size
820        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        // Initialize buffer that will be reused for responses
871        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            // Try to fill the buffer
877            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                // When encoded response is too large, remove one of the responses from it and try
906                // again
907                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                // Fill buffer with any overflown responses that may have been stored
961                buffer.extend(overflow_buffer.drain(..));
962
963                if index >= 1 {
964                    // Acknowledgements are received with delay
965                    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                // Unless `overflow_buffer` wasn't empty abort inner loop
1036                if buffer.is_empty() {
1037                    break;
1038                }
1039            }
1040        }
1041    }
1042
1043    /// Make notification without waiting for response
1044    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    /// Send a broadcast message
1062    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    /// Simple subscription that will produce decoded notifications, while skipping messages that
1087    /// fail to decode
1088    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    /// Simple subscription that will produce decoded broadcasts, while skipping messages that
1101    /// fail to decode
1102    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    /// Simple subscription that will produce decoded messages, while skipping messages that fail to
1115    /// decode
1116    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    /// Simple subscription that will produce decoded messages, while skipping messages that fail to
1142    /// decode
1143    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}