Skip to main content

rocketmq_client_rust/producer/
transaction_mq_producer.rs

1// Copyright 2023 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::collections::HashMap;
17use std::sync::Arc;
18
19use crate::ClientError;
20use cheetah_string::CheetahString;
21use rocketmq_model::common::message::message_ext::MessageExt;
22use rocketmq_model::common::message::message_queue::MessageQueue;
23use rocketmq_model::common::message::MessageTrait;
24
25use crate::base::query_result::QueryResult;
26use crate::producer::default_mq_producer::DefaultMQProducer;
27use crate::producer::producer_backend::ProducerBackend;
28use crate::producer::send_callback::ArcSendCallback;
29use crate::producer::send_result::SendResult;
30use crate::producer::transaction_listener::ArcTransactionListener;
31use crate::producer::transaction_listener::TransactionListener;
32use crate::producer::transaction_mq_produce_builder::TransactionMQProducerBuilder;
33use crate::producer::transaction_send_result::TransactionSendResult;
34use crate::runtime::ClientRuntime;
35use crate::session::ClientSession;
36use crate::session::ClientSessionProvider;
37
38/// Configuration for transaction message producer
39///
40/// Controls transaction check behavior, aligning with Java's TransactionMQProducer.
41#[derive(Clone)]
42pub struct TransactionProducerConfig {
43    /// Transaction listener for executing and checking local transactions
44    pub transaction_listener: Option<ArcTransactionListener>,
45
46    /// Deprecated Java-style transaction check listener facade.
47    pub transaction_check_listener: Option<ArcTransactionListener>,
48
49    /// Minimum size of transaction check thread pool (corresponds to Java checkThreadPoolMinSize)
50    ///
51    /// This controls concurrency admitted to the injected client runtime's blocking lane.
52    pub check_thread_pool_min_size: u32,
53
54    /// Maximum size of transaction check thread pool (corresponds to Java checkThreadPoolMaxSize)
55    ///
56    /// This controls concurrency admitted to the injected client runtime's blocking lane.
57    pub check_thread_pool_max_size: u32,
58
59    /// Maximum capacity of transaction check request queue (corresponds to Java
60    /// checkRequestHoldMax)
61    ///
62    /// This limits queued broker transaction check requests before worker execution.
63    /// Default: 2000
64    pub check_request_hold_max: u32,
65}
66
67impl Default for TransactionProducerConfig {
68    fn default() -> Self {
69        Self {
70            transaction_listener: None,
71            transaction_check_listener: None,
72            check_thread_pool_min_size: 1,
73            check_thread_pool_max_size: 1,
74            check_request_hold_max: 2000,
75        }
76    }
77}
78
79pub struct TransactionMQProducer {
80    default_producer: DefaultMQProducer,
81    transaction_producer_config: TransactionProducerConfig,
82}
83
84impl TransactionMQProducer {
85    pub fn builder(client_runtime: Arc<ClientRuntime>) -> TransactionMQProducerBuilder {
86        TransactionMQProducerBuilder::new(client_runtime)
87    }
88
89    #[must_use]
90    pub fn client_session(&self) -> Option<&ClientSession> {
91        self.default_producer.client_session()
92    }
93
94    pub(crate) fn new(
95        transaction_producer_config: TransactionProducerConfig,
96        default_producer: DefaultMQProducer,
97    ) -> Self {
98        Self {
99            default_producer,
100            transaction_producer_config,
101        }
102    }
103
104    pub(crate) fn default_producer_mut(&mut self) -> &mut DefaultMQProducer {
105        &mut self.default_producer
106    }
107
108    pub async fn start(&mut self) -> crate::ClientResult<()> {
109        <Self as ProducerBackend>::start(self).await
110    }
111
112    pub async fn shutdown(&mut self) {
113        <Self as ProducerBackend>::shutdown(self).await;
114    }
115
116    pub async fn send_message_in_transaction<T, M>(
117        &self,
118        msg: M,
119        arg: Option<T>,
120    ) -> crate::ClientResult<TransactionSendResult>
121    where
122        T: std::any::Any + Sync + Send,
123        M: MessageTrait + Send + Sync,
124    {
125        <Self as ProducerBackend>::send_message_in_transaction(self, msg, arg).await
126    }
127
128    pub fn set_transaction_listener(&mut self, transaction_listener: impl TransactionListener) {
129        self.set_transaction_listener_arc(Arc::new(transaction_listener));
130    }
131
132    pub fn transaction_listener(&self) -> Option<ArcTransactionListener> {
133        self.transaction_producer_config.transaction_listener.clone()
134    }
135
136    pub fn get_transaction_listener(&self) -> Option<ArcTransactionListener> {
137        self.transaction_listener()
138    }
139
140    pub fn transaction_check_listener(&self) -> Option<ArcTransactionListener> {
141        self.transaction_producer_config.transaction_check_listener.clone()
142    }
143
144    pub fn get_transaction_check_listener(&self) -> Option<ArcTransactionListener> {
145        self.transaction_check_listener()
146    }
147
148    pub fn set_transaction_check_listener(&mut self, transaction_check_listener: impl TransactionListener) {
149        self.set_transaction_check_listener_arc(Arc::new(transaction_check_listener));
150    }
151
152    pub fn set_transaction_check_listener_arc(&mut self, transaction_check_listener: ArcTransactionListener) {
153        self.transaction_producer_config.transaction_check_listener = Some(transaction_check_listener);
154    }
155
156    pub fn set_transaction_listener_arc(&mut self, transaction_listener: ArcTransactionListener) {
157        self.transaction_producer_config.transaction_listener = Some(transaction_listener.clone());
158        if let Some(default_mqproducer_impl) = self.default_producer.default_mqproducer_impl.as_ref() {
159            default_mqproducer_impl.set_transaction_listener(transaction_listener);
160        } else {
161            tracing::warn!("DefaultMQProducerImpl is not initialized; transaction listener stored in config");
162        }
163    }
164
165    pub fn check_thread_pool_min_size(&self) -> u32 {
166        self.transaction_producer_config.check_thread_pool_min_size
167    }
168
169    pub fn get_check_thread_pool_min_size(&self) -> u32 {
170        self.check_thread_pool_min_size()
171    }
172
173    pub fn set_check_thread_pool_min_size(&mut self, check_thread_pool_min_size: u32) {
174        self.transaction_producer_config.check_thread_pool_min_size = check_thread_pool_min_size;
175    }
176
177    pub fn check_thread_pool_max_size(&self) -> u32 {
178        self.transaction_producer_config.check_thread_pool_max_size
179    }
180
181    pub fn get_check_thread_pool_max_size(&self) -> u32 {
182        self.check_thread_pool_max_size()
183    }
184
185    pub fn set_check_thread_pool_max_size(&mut self, check_thread_pool_max_size: u32) {
186        self.transaction_producer_config.check_thread_pool_max_size = check_thread_pool_max_size;
187    }
188
189    pub fn check_request_hold_max(&self) -> u32 {
190        self.transaction_producer_config.check_request_hold_max
191    }
192
193    pub fn get_check_request_hold_max(&self) -> u32 {
194        self.check_request_hold_max()
195    }
196
197    pub fn set_check_request_hold_max(&mut self, check_request_hold_max: u32) {
198        self.transaction_producer_config.check_request_hold_max = check_request_hold_max;
199    }
200
201    #[inline]
202    pub fn is_use_tls(&self) -> bool {
203        self.default_producer.is_use_tls()
204    }
205
206    #[inline]
207    pub fn set_use_tls(&mut self, use_tls: bool) {
208        self.default_producer.set_use_tls(use_tls);
209    }
210}
211
212impl ClientSessionProvider for TransactionMQProducer {
213    fn client_session(&self) -> Option<&ClientSession> {
214        self.default_producer.client_session()
215    }
216}
217
218impl ProducerBackend for TransactionMQProducer {
219    async fn start(&mut self) -> crate::ClientResult<()> {
220        let transaction_listener = self.transaction_producer_config.transaction_listener.clone();
221        let default_mqproducer_impl = self
222            .default_producer
223            .default_mqproducer_impl
224            .as_ref()
225            .ok_or(ClientError::not_initialized("DefaultMQProducerImpl is not initialized"))?;
226        if let Some(transaction_listener) = transaction_listener {
227            default_mqproducer_impl.set_transaction_listener(transaction_listener);
228        }
229        default_mqproducer_impl.init_transaction_env(
230            self.transaction_producer_config.check_thread_pool_min_size,
231            self.transaction_producer_config.check_thread_pool_max_size,
232            self.transaction_producer_config.check_request_hold_max,
233        )?;
234        self.default_producer.start().await
235    }
236
237    async fn shutdown(&mut self) {
238        self.default_producer.shutdown().await;
239        if let Some(default_mqproducer_impl) = self.default_producer.default_mqproducer_impl.as_ref() {
240            default_mqproducer_impl.destroy_transaction_env().await;
241        }
242    }
243
244    async fn fetch_publish_message_queues(&mut self, topic: &str) -> crate::ClientResult<Vec<MessageQueue>> {
245        self.default_producer.fetch_publish_message_queues(topic).await
246    }
247
248    async fn create_topic(
249        &mut self,
250        key: &str,
251        new_topic: &str,
252        queue_num: i32,
253        attributes: HashMap<String, String>,
254    ) -> crate::ClientResult<()> {
255        self.default_producer
256            .create_topic(key, new_topic, queue_num, attributes)
257            .await
258    }
259
260    async fn create_topic_with_flag(
261        &mut self,
262        key: &str,
263        new_topic: &str,
264        queue_num: i32,
265        topic_sys_flag: i32,
266        attributes: HashMap<String, String>,
267    ) -> crate::ClientResult<()> {
268        self.default_producer
269            .create_topic_with_flag(key, new_topic, queue_num, topic_sys_flag, attributes)
270            .await
271    }
272
273    async fn search_offset(&mut self, mq: &MessageQueue, timestamp: u64) -> crate::ClientResult<i64> {
274        self.default_producer.search_offset(mq, timestamp).await
275    }
276
277    async fn max_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
278        self.default_producer.max_offset(mq).await
279    }
280
281    async fn min_offset(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
282        self.default_producer.min_offset(mq).await
283    }
284
285    async fn earliest_msg_store_time(&mut self, mq: &MessageQueue) -> crate::ClientResult<i64> {
286        self.default_producer.earliest_msg_store_time(mq).await
287    }
288
289    async fn query_message(
290        &mut self,
291        topic: &str,
292        key: &str,
293        max_num: i32,
294        begin: u64,
295        end: u64,
296    ) -> crate::ClientResult<QueryResult> {
297        self.default_producer
298            .query_message(topic, key, max_num, begin, end)
299            .await
300    }
301
302    async fn view_message(&mut self, topic: &str, msg_id: &str) -> crate::ClientResult<MessageExt> {
303        self.default_producer.view_message(topic, msg_id).await
304    }
305
306    async fn send<M>(&self, msg: M) -> crate::ClientResult<Option<SendResult>>
307    where
308        M: MessageTrait + Send + Sync,
309    {
310        self.default_producer.send(msg).await
311    }
312
313    async fn send_with_timeout<M>(&self, msg: M, timeout: u64) -> crate::ClientResult<Option<SendResult>>
314    where
315        M: MessageTrait + Send + Sync,
316    {
317        self.default_producer.send_with_timeout(msg, timeout).await
318    }
319
320    async fn send_with_callback<M, F>(&self, msg: M, send_callback: F) -> crate::ClientResult<()>
321    where
322        M: MessageTrait + Send + Sync,
323        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
324    {
325        self.default_producer.send_with_callback(msg, send_callback).await
326    }
327
328    async fn send_with_callback_timeout<F, M>(&self, msg: M, send_callback: F, timeout: u64) -> crate::ClientResult<()>
329    where
330        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
331        M: MessageTrait + Send + Sync,
332    {
333        self.default_producer
334            .send_with_callback_timeout(msg, send_callback, timeout)
335            .await
336    }
337
338    async fn send_oneway<M>(&self, msg: M) -> crate::ClientResult<()>
339    where
340        M: MessageTrait + Send + Sync,
341    {
342        self.default_producer.send_oneway(msg).await
343    }
344
345    async fn send_to_queue<M>(&self, msg: M, mq: MessageQueue) -> crate::ClientResult<Option<SendResult>>
346    where
347        M: MessageTrait + Send + Sync,
348    {
349        self.default_producer.send_to_queue(msg, mq).await
350    }
351
352    async fn send_to_queue_with_timeout<M>(
353        &self,
354        msg: M,
355        mq: MessageQueue,
356        timeout: u64,
357    ) -> crate::ClientResult<Option<SendResult>>
358    where
359        M: MessageTrait + Send + Sync,
360    {
361        self.default_producer.send_to_queue_with_timeout(msg, mq, timeout).await
362    }
363
364    async fn send_to_queue_with_callback<M, F>(
365        &self,
366        msg: M,
367        mq: MessageQueue,
368        send_callback: F,
369    ) -> crate::ClientResult<()>
370    where
371        M: MessageTrait + Send + Sync,
372        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
373    {
374        self.default_producer
375            .send_to_queue_with_callback(msg, mq, send_callback)
376            .await
377    }
378
379    async fn send_to_queue_with_callback_timeout<M, F>(
380        &self,
381        msg: M,
382        mq: MessageQueue,
383        send_callback: F,
384        timeout: u64,
385    ) -> crate::ClientResult<()>
386    where
387        M: MessageTrait + Send + Sync,
388        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
389    {
390        self.default_producer
391            .send_to_queue_with_callback_timeout(msg, mq, send_callback, timeout)
392            .await
393    }
394
395    async fn send_oneway_to_queue<M>(&self, msg: M, mq: MessageQueue) -> crate::ClientResult<()>
396    where
397        M: MessageTrait + Send + Sync,
398    {
399        self.default_producer.send_oneway_to_queue(msg, mq).await
400    }
401
402    async fn send_with_selector<M, S, T>(&self, msg: M, selector: S, arg: T) -> crate::ClientResult<Option<SendResult>>
403    where
404        M: MessageTrait + Send + Sync,
405        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync,
406        T: Send + Sync,
407    {
408        self.default_producer.send_with_selector(msg, selector, arg).await
409    }
410
411    async fn send_with_selector_timeout<M, S, T>(
412        &self,
413        msg: M,
414        selector: S,
415        arg: T,
416        timeout: u64,
417    ) -> crate::ClientResult<Option<SendResult>>
418    where
419        M: MessageTrait + Send + Sync,
420        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync,
421        T: Send + Sync,
422    {
423        self.default_producer
424            .send_with_selector_timeout(msg, selector, arg, timeout)
425            .await
426    }
427
428    async fn send_with_selector_callback<M, S, T>(
429        &self,
430        msg: M,
431        selector: S,
432        arg: T,
433        send_callback: Option<ArcSendCallback>,
434    ) -> crate::ClientResult<()>
435    where
436        M: MessageTrait + Send + Sync,
437        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync,
438        T: Send + Sync,
439    {
440        self.default_producer
441            .send_with_selector_callback(msg, selector, arg, send_callback)
442            .await
443    }
444
445    async fn send_with_selector_callback_timeout<M, S, T>(
446        &self,
447        msg: M,
448        selector: S,
449        arg: T,
450        send_callback: Option<ArcSendCallback>,
451        timeout: u64,
452    ) -> crate::ClientResult<()>
453    where
454        M: MessageTrait + Send + Sync,
455        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync + 'static,
456        T: Send + Sync + 'static,
457    {
458        self.default_producer
459            .send_with_selector_callback_timeout(msg, selector, arg, send_callback, timeout)
460            .await
461    }
462
463    async fn send_oneway_with_selector<M, S, T>(&self, msg: M, selector: S, arg: T) -> crate::ClientResult<()>
464    where
465        M: MessageTrait + Send + Sync,
466        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync + 'static,
467        T: Send + Sync + 'static,
468    {
469        self.default_producer
470            .send_oneway_with_selector(msg, selector, arg)
471            .await
472    }
473
474    async fn send_message_in_transaction<T, M>(
475        &self,
476        mut msg: M,
477        arg: Option<T>,
478    ) -> crate::ClientResult<TransactionSendResult>
479    where
480        T: std::any::Any + Sync + Send,
481        M: MessageTrait + Send + Sync,
482    {
483        let transaction_listener = self
484            .transaction_producer_config
485            .transaction_listener
486            .clone()
487            .ok_or_else(|| crate::mq_client_err!("TransactionListener is null"))?;
488
489        msg.set_topic(self.default_producer.with_namespace(msg.topic()));
490        let default_mqproducer_impl =
491            self.default_producer
492                .default_mqproducer_impl
493                .as_ref()
494                .ok_or(crate::ClientError::not_initialized(
495                    "DefaultMQProducerImpl is not initialized",
496                ))?;
497        default_mqproducer_impl.set_transaction_listener(transaction_listener);
498        default_mqproducer_impl
499            .send_message_in_transaction(msg, arg.map(|x| Box::new(x) as Box<dyn Any + Sync + Send>))
500            .await
501    }
502
503    async fn send_batch<M>(&self, msgs: Vec<M>) -> crate::ClientResult<SendResult>
504    where
505        M: MessageTrait + Send + Sync,
506    {
507        self.default_producer.send_batch(msgs).await
508    }
509
510    async fn send_batch_with_timeout<M>(&self, msgs: Vec<M>, timeout: u64) -> crate::ClientResult<SendResult>
511    where
512        M: MessageTrait + Send + Sync,
513    {
514        self.default_producer.send_batch_with_timeout(msgs, timeout).await
515    }
516
517    async fn send_batch_to_queue<M>(&self, msgs: Vec<M>, mq: MessageQueue) -> crate::ClientResult<SendResult>
518    where
519        M: MessageTrait + Send + Sync,
520    {
521        self.default_producer.send_batch_to_queue(msgs, mq).await
522    }
523
524    async fn send_batch_to_queue_with_timeout<M>(
525        &self,
526        msgs: Vec<M>,
527        mq: MessageQueue,
528        timeout: u64,
529    ) -> crate::ClientResult<SendResult>
530    where
531        M: MessageTrait + Send + Sync,
532    {
533        self.default_producer
534            .send_batch_to_queue_with_timeout(msgs, mq, timeout)
535            .await
536    }
537
538    async fn send_batch_with_callback<M, F>(&self, msgs: Vec<M>, f: F) -> crate::ClientResult<()>
539    where
540        M: MessageTrait + Send + Sync,
541        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
542    {
543        self.default_producer.send_batch_with_callback(msgs, f).await
544    }
545
546    async fn send_batch_with_callback_timeout<M, F>(&self, msgs: Vec<M>, f: F, timeout: u64) -> crate::ClientResult<()>
547    where
548        M: MessageTrait + Send + Sync,
549        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
550    {
551        self.default_producer
552            .send_batch_with_callback_timeout(msgs, f, timeout)
553            .await
554    }
555
556    async fn send_batch_to_queue_with_callback<M, F>(
557        &self,
558        msgs: Vec<M>,
559        mq: MessageQueue,
560        f: F,
561    ) -> crate::ClientResult<()>
562    where
563        M: MessageTrait + Send + Sync,
564        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
565    {
566        self.default_producer
567            .send_batch_to_queue_with_callback(msgs, mq, f)
568            .await
569    }
570
571    async fn send_batch_to_queue_with_callback_timeout<M, F>(
572        &self,
573        msgs: Vec<M>,
574        mq: MessageQueue,
575        f: F,
576        timeout: u64,
577    ) -> crate::ClientResult<()>
578    where
579        M: MessageTrait + Send + Sync,
580        F: Fn(Option<&SendResult>, Option<&ClientError>) + Send + Sync + 'static,
581    {
582        self.default_producer
583            .send_batch_to_queue_with_callback_timeout(msgs, mq, f, timeout)
584            .await
585    }
586
587    async fn request<M>(&self, msg: M, timeout: u64) -> crate::ClientResult<Box<dyn MessageTrait + Send>>
588    where
589        M: MessageTrait + Send + Sync,
590    {
591        self.default_producer.request(msg, timeout).await
592    }
593
594    async fn request_with_callback<F, M>(&self, msg: M, request_callback: F, timeout: u64) -> crate::ClientResult<()>
595    where
596        F: Fn(Option<&dyn MessageTrait>, Option<&crate::ClientError>) + Send + Sync + 'static,
597        M: MessageTrait + Send + Sync,
598    {
599        self.default_producer
600            .request_with_callback(msg, request_callback, timeout)
601            .await
602    }
603
604    async fn request_with_selector<M, S, T>(
605        &self,
606        msg: M,
607        selector: S,
608        arg: T,
609        timeout: u64,
610    ) -> crate::ClientResult<Box<dyn MessageTrait + Send>>
611    where
612        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync + 'static,
613        T: Send + Sync + 'static,
614        M: MessageTrait + Send + Sync,
615    {
616        self.default_producer
617            .request_with_selector(msg, selector, arg, timeout)
618            .await
619    }
620
621    async fn request_with_selector_callback<M, S, T, F>(
622        &self,
623        msg: M,
624        selector: S,
625        arg: T,
626        request_callback: F,
627        timeout: u64,
628    ) -> crate::ClientResult<()>
629    where
630        S: Fn(&[MessageQueue], &M, &T) -> Option<MessageQueue> + Send + Sync + 'static,
631        F: Fn(Option<&dyn MessageTrait>, Option<&crate::ClientError>) + Send + Sync + 'static,
632        T: Send + Sync + 'static,
633        M: MessageTrait + Send + Sync,
634    {
635        self.default_producer
636            .request_with_selector_callback(msg, selector, arg, request_callback, timeout)
637            .await
638    }
639
640    async fn request_to_queue<M>(
641        &self,
642        msg: M,
643        mq: MessageQueue,
644        timeout: u64,
645    ) -> crate::ClientResult<Box<dyn MessageTrait + Send>>
646    where
647        M: MessageTrait + Send + Sync,
648    {
649        self.default_producer.request_to_queue(msg, mq, timeout).await
650    }
651
652    async fn request_to_queue_with_callback<M, F>(
653        &self,
654        msg: M,
655        mq: MessageQueue,
656        request_callback: F,
657        timeout: u64,
658    ) -> crate::ClientResult<()>
659    where
660        F: Fn(Option<&dyn MessageTrait>, Option<&crate::ClientError>) + Send + Sync + 'static,
661        M: MessageTrait + Send + Sync,
662    {
663        self.default_producer
664            .request_to_queue_with_callback(msg, mq, request_callback, timeout)
665            .await
666    }
667
668    async fn recall_message(
669        &self,
670        topic: impl Into<CheetahString>,
671        recall_handle: impl Into<CheetahString>,
672    ) -> crate::ClientResult<String> {
673        self.default_producer.recall_message(topic, recall_handle).await
674    }
675
676    fn as_any(&self) -> &dyn Any {
677        self
678    }
679
680    fn as_any_mut(&mut self) -> &mut dyn Any {
681        self
682    }
683}
684
685#[cfg(test)]
686mod tests {
687    use super::*;
688
689    #[test]
690    fn java_getter_aliases_delegate_to_transaction_config() {
691        let producer =
692            TransactionMQProducer::builder(crate::runtime::test_client_runtime("transaction-producer-getter-test"))
693                .build();
694
695        assert!(producer.get_transaction_listener().is_none());
696    }
697
698    #[test]
699    fn use_tls_facade_and_builder_delegate_to_default_producer_like_java_client_config() {
700        let mut producer =
701            TransactionMQProducer::builder(crate::runtime::test_client_runtime("transaction-producer-test"))
702                .producer_group("transaction_tls_group")
703                .use_tls(true)
704                .build();
705
706        assert!(producer.is_use_tls());
707        assert!(producer.default_producer.is_use_tls());
708        assert!(producer
709            .default_producer
710            .default_mqproducer_impl
711            .as_ref()
712            .expect("producer impl should exist")
713            .is_use_tls());
714
715        producer.set_use_tls(false);
716
717        assert!(!producer.is_use_tls());
718        assert!(!producer.default_producer.is_use_tls());
719        assert!(!producer
720            .default_producer
721            .default_mqproducer_impl
722            .as_ref()
723            .expect("producer impl should exist")
724            .is_use_tls());
725    }
726}