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