Skip to main content

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