Skip to main content

sz_orm_queue/
queue.rs

1use crate::error::MqError;
2use async_trait::async_trait;
3use serde::{Deserialize, Serialize};
4use std::collections::{HashMap, VecDeque};
5use std::sync::Arc;
6use std::time::{Duration, Instant};
7use tokio::sync::{Notify, RwLock};
8
9// ============================================================================
10// 核心 Trait
11// ============================================================================
12
13/// 消息队列统一抽象
14///
15/// 提供发布/消费/确认/订阅四个核心方法,
16/// 以及 nack(重试)和 reject(死信)两个扩展方法(带默认实现,向后兼容)。
17#[async_trait]
18pub trait MessageQueue: Send + Sync {
19    /// 发布消息到指定 topic
20    async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError>;
21
22    /// 从指定 topic 消费一条消息(消息进入 in_flight 状态)
23    async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError>;
24
25    /// 确认消息已处理完成(从 in_flight 移除)
26    async fn ack(&self, message_id: &str) -> Result<(), MqError>;
27
28    /// 订阅 topic
29    async fn subscribe(&self, topic: &str) -> Result<(), MqError>;
30
31    /// 消息重回队列尾部(带重试次数追踪)
32    ///
33    /// - 将消息从 in_flight 移回原 topic 队列尾部,retry_count + 1
34    /// - 当 retry_count 达到 max_retries 时自动转入死信队列
35    ///
36    /// 默认实现返回 NotSupported 错误(保持向后兼容)。
37    async fn nack(&self, _message_id: &str) -> Result<(), MqError> {
38        Err(MqError::NotSupported("nack not supported".to_string()))
39    }
40
41    /// 消息直接进入死信队列(不重试,不增加 retry_count)
42    ///
43    /// 默认实现返回 NotSupported 错误(保持向后兼容)。
44    async fn reject(&self, _message_id: &str) -> Result<(), MqError> {
45        Err(MqError::NotSupported("reject not supported".to_string()))
46    }
47}
48
49// ============================================================================
50// 消息
51// ============================================================================
52
53/// 消息体
54///
55/// 包含 topic、payload、key、timestamp、headers、id 以及重试次数 retry_count。
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct Message {
58    pub topic: String,
59    pub payload: Vec<u8>,
60    pub key: Option<String>,
61    pub timestamp: i64,
62    pub headers: HashMap<String, String>,
63    #[serde(default)]
64    pub id: String,
65    /// 重试次数(nack 时递增,达到 max_retries 后转入死信队列)
66    #[serde(default)]
67    pub retry_count: u32,
68}
69
70impl Message {
71    pub fn new(topic: impl Into<String>, payload: Vec<u8>) -> Self {
72        Self {
73            topic: topic.into(),
74            payload,
75            key: None,
76            timestamp: current_timestamp(),
77            headers: HashMap::new(),
78            id: String::new(),
79            retry_count: 0,
80        }
81    }
82
83    pub fn with_key(mut self, key: impl Into<String>) -> Self {
84        self.key = Some(key.into());
85        self
86    }
87
88    pub fn text(&self) -> Option<&str> {
89        std::str::from_utf8(&self.payload).ok()
90    }
91
92    pub fn json<T: serde::de::DeserializeOwned>(&self) -> Option<T> {
93        serde_json::from_slice(&self.payload).ok()
94    }
95
96    pub fn text_message(topic: impl Into<String>, text: impl Into<String>) -> Self {
97        Self::new(topic, text.into().into_bytes())
98    }
99
100    pub fn json_message<T: serde::Serialize>(
101        topic: impl Into<String>,
102        data: &T,
103    ) -> Result<Self, MqError> {
104        let payload = serde_json::to_vec(data)?;
105        Ok(Self::new(topic, payload))
106    }
107}
108
109/// 当前时间戳(毫秒)
110///
111/// M-10 修复:使用 `unwrap_or_default()` 会在系统时间早于 UNIX_EPOCH 时返回 0,
112/// 隐藏了潜在的时钟回拨问题。改为显式 match 并通过 eprintln! 记录事件,
113/// 便于在生产环境中排查(可被 stderr 重定向到日志收集系统)。
114fn current_timestamp() -> i64 {
115    use std::time::{SystemTime, UNIX_EPOCH};
116    match SystemTime::now().duration_since(UNIX_EPOCH) {
117        Ok(d) => d.as_millis() as i64,
118        Err(e) => {
119            // 系统时间早于 UNIX_EPOCH(时钟回拨或系统错误)
120            // 返回 0 作为兜底,避免 panic;生产环境应监控此事件
121            eprintln!(
122                "WARN: current_timestamp: system time before UNIX_EPOCH: {} (duration_secs={})",
123                e,
124                e.duration().as_secs()
125            );
126            0
127        }
128    }
129}
130
131// ============================================================================
132// 配置
133// ============================================================================
134
135pub struct QueueConfig {
136    pub provider: MqProvider,
137    pub brokers: Vec<String>,
138    pub group_id: Option<String>,
139    pub username: Option<String>,
140    pub password: Option<String>,
141}
142
143impl Default for QueueConfig {
144    fn default() -> Self {
145        Self {
146            provider: MqProvider::Kafka(KafkaConfig::default()),
147            brokers: vec!["localhost:9092".to_string()],
148            group_id: None,
149            username: None,
150            password: None,
151        }
152    }
153}
154
155impl QueueConfig {
156    pub fn new() -> Self {
157        Self::default()
158    }
159
160    pub fn with_provider(mut self, provider: MqProvider) -> Self {
161        self.provider = provider;
162        self
163    }
164
165    pub fn with_brokers(mut self, brokers: Vec<String>) -> Self {
166        self.brokers = brokers;
167        self
168    }
169
170    pub fn with_group(mut self, group: impl Into<String>) -> Self {
171        self.group_id = Some(group.into());
172        self
173    }
174
175    pub fn with_auth(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
176        self.username = Some(username.into());
177        self.password = Some(password.into());
178        self
179    }
180}
181
182#[derive(Debug, Clone)]
183pub enum MqProvider {
184    Kafka(KafkaConfig),
185    RabbitMQ(RabbitConfig),
186    RocketMQ(RocketConfig),
187    ActiveMQ(ActiveConfig),
188    Nats(NatsConfig),
189    Pulsar(PulsarConfig),
190}
191
192#[derive(Debug, Clone, Default)]
193pub struct KafkaConfig {
194    pub client_id: Option<String>,
195    pub acks: Option<String>,
196    pub retries: Option<u32>,
197}
198
199#[derive(Debug, Clone, Default)]
200pub struct RabbitConfig {
201    pub virtual_host: Option<String>,
202}
203
204#[derive(Debug, Clone, Default)]
205pub struct RocketConfig {
206    pub namespace: Option<String>,
207}
208
209#[derive(Debug, Clone, Default)]
210pub struct ActiveConfig {
211    pub broker_url: Option<String>,
212}
213
214#[derive(Debug, Clone, Default)]
215pub struct NatsConfig {
216    pub name: Option<String>,
217}
218
219#[derive(Debug, Clone, Default)]
220pub struct PulsarConfig {
221    pub service_url: Option<String>,
222}
223
224// ============================================================================
225// 重连策略(ReconnectPolicy)
226// ============================================================================
227
228/// 重连策略(指数退避)
229///
230/// 用于 `QueueWrapper::with_reconnect`,在网络错误(`MqError::Connection`)时自动重试。
231///
232/// - `max_retries`:最大重试次数(默认 5)
233/// - `initial_delay_ms`:初始延迟毫秒(默认 100)
234/// - `max_delay_ms`:最大延迟毫秒(默认 10000)
235/// - `multiplier`:退避倍数(默认 2.0,指数退避)
236#[derive(Debug, Clone)]
237pub struct ReconnectPolicy {
238    /// 最大重试次数(默认 5)
239    pub max_retries: u32,
240    /// 初始延迟(毫秒,默认 100)
241    pub initial_delay_ms: u64,
242    /// 最大延迟(毫秒,默认 10000)
243    pub max_delay_ms: u64,
244    /// 退避倍数(默认 2.0,指数退避)
245    pub multiplier: f64,
246}
247
248impl Default for ReconnectPolicy {
249    fn default() -> Self {
250        Self {
251            max_retries: 5,
252            initial_delay_ms: 100,
253            max_delay_ms: 10_000,
254            multiplier: 2.0,
255        }
256    }
257}
258
259impl ReconnectPolicy {
260    pub fn new() -> Self {
261        Self::default()
262    }
263
264    /// 计算第 `attempt` 次重试的延迟(指数退避,封顶 max_delay_ms)
265    ///
266    /// - `attempt = 0`:返回 `initial_delay_ms`
267    /// - `attempt = 1`:返回 `initial_delay_ms * multiplier`
268    /// - 以此类推,但不超过 `max_delay_ms`
269    ///
270    /// 使用 `max(0.0)` 防止负数 multiplier 导致负延迟。
271    pub fn next_delay(&self, attempt: u32) -> Duration {
272        let delay_ms = (self.initial_delay_ms as f64) * self.multiplier.powi(attempt as i32);
273        // 防止负数或 NaN,封顶 max_delay_ms
274        let delay_ms = delay_ms.max(0.0).min(self.max_delay_ms as f64);
275        Duration::from_millis(delay_ms as u64)
276    }
277}
278
279/// 重连状态追踪
280///
281/// 用于记录当前重连次数和上次重连时间,供外部监控使用。
282#[derive(Debug, Clone, Default)]
283pub struct ReconnectState {
284    /// 当前重连次数
285    pub attempts: u32,
286    /// 上次重连时间
287    pub last_reconnect: Option<Instant>,
288}
289
290// ============================================================================
291// 背压策略(BackpressurePolicy)
292// ============================================================================
293
294/// 背压策略
295///
296/// 用于 `InMemoryQueue::with_backpressure`,控制队列满时的行为。
297///
298/// - `max_queue_size`:每 topic 最大队列长度(默认 10000)
299/// - `on_overflow`:队列满时的溢出处理策略
300#[derive(Debug, Clone)]
301pub struct BackpressurePolicy {
302    /// 每 topic 最大队列长度(默认 10000)
303    pub max_queue_size: usize,
304    /// 队列满时的溢出处理策略
305    pub on_overflow: OverflowStrategy,
306}
307
308impl Default for BackpressurePolicy {
309    fn default() -> Self {
310        Self {
311            max_queue_size: 10_000,
312            on_overflow: OverflowStrategy::Reject,
313        }
314    }
315}
316
317/// 溢出处理策略
318///
319/// - `Block`:阻塞等待(async,直到队列有空间)
320/// - `DropOldest`:丢弃最旧消息后插入新的
321/// - `DropNewest`:丢弃新消息(返回 Ok,不插入)
322/// - `Reject`:拒绝(返回 Err)
323#[derive(Debug, Clone, Copy, PartialEq, Eq)]
324pub enum OverflowStrategy {
325    /// 阻塞等待(async,直到队列有空间)
326    Block,
327    /// 丢弃最旧消息后插入新的
328    DropOldest,
329    /// 丢弃新消息(返回 Ok,不插入)
330    DropNewest,
331    /// 拒绝(返回 Err)
332    Reject,
333}
334
335// ============================================================================
336// InMemoryQueue
337// ============================================================================
338
339pub struct InMemoryQueue {
340    inner: Arc<RwLock<InMemoryQueueInner>>,
341}
342
343impl Clone for InMemoryQueue {
344    fn clone(&self) -> Self {
345        Self {
346            inner: Arc::clone(&self.inner),
347        }
348    }
349}
350
351struct InMemoryQueueInner {
352    /// 按 topic 分组的就绪队列
353    queues: HashMap<String, VecDeque<Message>>,
354    /// 已消费未确认的消息(按 message_id 索引)
355    in_flight: HashMap<String, Message>,
356    /// 按 topic 分组的订阅者计数
357    subscribers: HashMap<String, usize>,
358    /// 下一个消息 ID(自增)
359    next_id: u64,
360    /// H-3 修复:每个 topic 最大消息数限制(防止 OOM)
361    /// 默认 100,000,可通过 `with_max_messages_per_topic` 调整
362    max_messages_per_topic: usize,
363    /// 死信队列:按 topic 分组
364    dead_letters: HashMap<String, VecDeque<Message>>,
365    /// 最大重试次数(默认 3,nack 达到此值后转入死信队列)
366    max_retries: u32,
367    /// 背压策略(None 时使用 max_messages_per_topic + Reject 行为,保持向后兼容)
368    backpressure: Option<BackpressurePolicy>,
369    /// Block 策略的通知器(按 topic)
370    notify: HashMap<String, Arc<Notify>>,
371}
372
373/// 默认每 topic 最大消息数(H-3 修复)
374const DEFAULT_MAX_MESSAGES_PER_TOPIC: usize = 100_000;
375
376/// 默认最大重试次数
377const DEFAULT_MAX_RETRIES: u32 = 3;
378
379impl InMemoryQueue {
380    pub fn new() -> Self {
381        Self::with_max_messages_per_topic(DEFAULT_MAX_MESSAGES_PER_TOPIC)
382    }
383
384    /// 创建指定每 topic 最大消息数的队列(H-3 修复)
385    ///
386    /// 当队列中消息数达到此限制时,`publish` 将返回 `MqError::Publish` 错误。
387    /// 默认 100,000,可根据内存容量调整。
388    pub fn with_max_messages_per_topic(max: usize) -> Self {
389        Self {
390            inner: Arc::new(RwLock::new(InMemoryQueueInner {
391                queues: HashMap::new(),
392                in_flight: HashMap::new(),
393                subscribers: HashMap::new(),
394                next_id: 1,
395                max_messages_per_topic: max,
396                dead_letters: HashMap::new(),
397                max_retries: DEFAULT_MAX_RETRIES,
398                backpressure: None,
399                notify: HashMap::new(),
400            })),
401        }
402    }
403
404    /// 创建指定最大重试次数的队列
405    ///
406    /// - `max_retries = 3`(默认):允许 3 次 nack 重试,第 3 次 nack 转入死信队列
407    /// - `max_retries = 0`:不允许重试,第一次 nack 即转入死信队列
408    pub fn with_max_retries(max_retries: u32) -> Self {
409        Self {
410            inner: Arc::new(RwLock::new(InMemoryQueueInner {
411                queues: HashMap::new(),
412                in_flight: HashMap::new(),
413                subscribers: HashMap::new(),
414                next_id: 1,
415                max_messages_per_topic: DEFAULT_MAX_MESSAGES_PER_TOPIC,
416                dead_letters: HashMap::new(),
417                max_retries,
418                backpressure: None,
419                notify: HashMap::new(),
420            })),
421        }
422    }
423
424    /// 创建带背压策略的队列
425    ///
426    /// `policy.max_queue_size` 将同时设置 `max_messages_per_topic`,
427    /// 确保背压策略与 H-3 限制一致。
428    pub fn with_backpressure(policy: BackpressurePolicy) -> Self {
429        let max = policy.max_queue_size;
430        Self {
431            inner: Arc::new(RwLock::new(InMemoryQueueInner {
432                queues: HashMap::new(),
433                in_flight: HashMap::new(),
434                subscribers: HashMap::new(),
435                next_id: 1,
436                max_messages_per_topic: max,
437                dead_letters: HashMap::new(),
438                max_retries: DEFAULT_MAX_RETRIES,
439                backpressure: Some(policy),
440                notify: HashMap::new(),
441            })),
442        }
443    }
444
445    pub async fn message_count(&self, topic: &str) -> usize {
446        let inner = self.inner.read().await;
447        inner.queues.get(topic).map(|q| q.len()).unwrap_or(0)
448    }
449
450    pub async fn subscriber_count(&self, topic: &str) -> usize {
451        let inner = self.inner.read().await;
452        *inner.subscribers.get(topic).unwrap_or(&0)
453    }
454
455    pub async fn in_flight_count(&self) -> usize {
456        let inner = self.inner.read().await;
457        inner.in_flight.len()
458    }
459
460    /// 死信队列中的消息数(指定 topic)
461    ///
462    /// 如果 topic 不存在死信队列,返回 0。
463    pub async fn dead_letter_count(&self, topic: &str) -> usize {
464        let inner = self.inner.read().await;
465        inner.dead_letters.get(topic).map(|q| q.len()).unwrap_or(0)
466    }
467
468    /// 消费一条死信消息(从死信队列头部弹出)
469    ///
470    /// 注意:此操作不会增加 in_flight 计数,死信消息不再走正常 ack 流程。
471    /// 返回 `None` 表示该 topic 没有死信消息。
472    pub async fn consume_dead_letter(&self, topic: &str) -> Option<Message> {
473        let mut inner = self.inner.write().await;
474        if let Some(dq) = inner.dead_letters.get_mut(topic) {
475            return dq.pop_front();
476        }
477        None
478    }
479
480    /// 收集所有 topic 的死信消息(用于 DLX 自动重投递)
481    ///
482    /// 返回所有死信队列中消息的克隆副本,不修改原队列。
483    pub async fn collect_all_dead_letters(&self) -> Vec<Message> {
484        let inner = self.inner.read().await;
485        let mut result = Vec::new();
486        for dq in inner.dead_letters.values() {
487            for msg in dq {
488                result.push(msg.clone());
489            }
490        }
491        result
492    }
493
494    /// 从死信队列中移除指定消息(用于 DLX 自动重投递)
495    ///
496    /// 在所有 topic 的死信队列中查找指定 `message_id` 并移除。
497    /// 返回 `true` 表示找到并移除,`false` 表示未找到。
498    pub async fn remove_dead_letter(&self, message_id: &str) -> bool {
499        let mut inner = self.inner.write().await;
500        for dq in inner.dead_letters.values_mut() {
501            if let Some(pos) = dq.iter().position(|m| m.id == message_id) {
502                dq.remove(pos);
503                return true;
504            }
505        }
506        false
507    }
508
509    /// 将死信消息重新放回原 topic 队列(重置 retry_count = 0)
510    ///
511    /// 在所有 topic 的死信队列中查找指定 `message_id`。
512    /// 找到后从死信队列移除,重置 retry_count,放回原 topic 队列尾部。
513    pub async fn requeue_dead_letter(&self, message_id: &str) -> Result<(), MqError> {
514        let mut inner = self.inner.write().await;
515        // 遍历所有 topic 的死信队列查找消息
516        for dq in inner.dead_letters.values_mut() {
517            let mut found_idx = None;
518            for (idx, m) in dq.iter().enumerate() {
519                if m.id == message_id {
520                    found_idx = Some(idx);
521                    break;
522                }
523            }
524            if let Some(idx) = found_idx {
525                let mut msg = dq.remove(idx).expect("checked: idx exists");
526                // 重置重试次数
527                msg.retry_count = 0;
528                // 重新放入原 topic 队列尾部
529                inner
530                    .queues
531                    .entry(msg.topic.clone())
532                    .or_insert_with(VecDeque::new)
533                    .push_back(msg);
534                return Ok(());
535            }
536        }
537        Err(MqError::NotSupported(format!(
538            "Dead letter not found: {}",
539            message_id
540        )))
541    }
542}
543
544impl Default for InMemoryQueue {
545    fn default() -> Self {
546        Self::new()
547    }
548}
549
550#[async_trait]
551impl MessageQueue for InMemoryQueue {
552    async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError> {
553        // 获取背压策略(如果有);None 时使用 Reject(保持 H-3 向后兼容)
554        let strategy = {
555            let inner = self.inner.read().await;
556            inner
557                .backpressure
558                .as_ref()
559                .map(|p| p.on_overflow)
560                .unwrap_or(OverflowStrategy::Reject)
561        };
562
563        match strategy {
564            OverflowStrategy::Block => self.publish_with_block(topic, message).await,
565            _ => self.publish_immediate(topic, message, strategy).await,
566        }
567    }
568
569    async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError> {
570        let mut inner = self.inner.write().await;
571        let queue = inner
572            .queues
573            .entry(topic.to_string())
574            .or_insert_with(VecDeque::new);
575        if let Some(msg) = queue.pop_front() {
576            inner.in_flight.insert(msg.id.clone(), msg.clone());
577            // 通知等待的 publisher(Block 策略):队列有空间了
578            if let Some(notify) = inner.notify.get(topic) {
579                notify.notify_one();
580            }
581            Ok(Some(msg))
582        } else {
583            Ok(None)
584        }
585    }
586
587    async fn ack(&self, message_id: &str) -> Result<(), MqError> {
588        let mut inner = self.inner.write().await;
589        inner.in_flight.remove(message_id).ok_or_else(|| {
590            MqError::NotSupported(format!("Message not found for ack: {}", message_id))
591        })?;
592        Ok(())
593    }
594
595    async fn subscribe(&self, topic: &str) -> Result<(), MqError> {
596        let mut inner = self.inner.write().await;
597        *inner.subscribers.entry(topic.to_string()).or_insert(0) += 1;
598        Ok(())
599    }
600
601    async fn nack(&self, message_id: &str) -> Result<(), MqError> {
602        let mut inner = self.inner.write().await;
603        let mut msg = inner.in_flight.remove(message_id).ok_or_else(|| {
604            MqError::NotSupported(format!("Message not found for nack: {}", message_id))
605        })?;
606
607        // 增加重试次数(saturating_add 防止 u32 溢出)
608        msg.retry_count = msg.retry_count.saturating_add(1);
609
610        // 检查是否达到最大重试次数:达到则转入死信队列
611        if msg.retry_count >= inner.max_retries {
612            inner
613                .dead_letters
614                .entry(msg.topic.clone())
615                .or_insert_with(VecDeque::new)
616                .push_back(msg);
617        } else {
618            // 未达到上限:重回原 topic 队列尾部等待再次消费
619            // 注意:nack 增加了队列长度,不通知 Block publisher(避免唤醒后立即又满)
620            inner
621                .queues
622                .entry(msg.topic.clone())
623                .or_insert_with(VecDeque::new)
624                .push_back(msg);
625        }
626        Ok(())
627    }
628
629    async fn reject(&self, message_id: &str) -> Result<(), MqError> {
630        let mut inner = self.inner.write().await;
631        let msg = inner.in_flight.remove(message_id).ok_or_else(|| {
632            MqError::NotSupported(format!("Message not found for reject: {}", message_id))
633        })?;
634        // 直接进入死信队列(不增加 retry_count)
635        inner
636            .dead_letters
637            .entry(msg.topic.clone())
638            .or_insert_with(VecDeque::new)
639            .push_back(msg);
640        Ok(())
641    }
642}
643
644impl InMemoryQueue {
645    /// 立即模式 publish:根据溢出策略处理满队列
646    ///
647    /// 用于 Reject / DropOldest / DropNewest 策略。
648    async fn publish_immediate(
649        &self,
650        topic: &str,
651        message: &[u8],
652        strategy: OverflowStrategy,
653    ) -> Result<(), MqError> {
654        let mut inner = self.inner.write().await;
655        // H-3 修复:检查消息数限制,防止 OOM
656        let current_count = inner.queues.get(topic).map(|q| q.len()).unwrap_or(0);
657        if current_count >= inner.max_messages_per_topic {
658            match strategy {
659                OverflowStrategy::DropOldest => {
660                    // 弹出最旧消息后插入新的
661                    let queue = inner
662                        .queues
663                        .entry(topic.to_string())
664                        .or_insert_with(VecDeque::new);
665                    queue.pop_front();
666                }
667                OverflowStrategy::DropNewest => {
668                    // 丢弃新消息,直接返回 Ok
669                    return Ok(());
670                }
671                OverflowStrategy::Reject => {
672                    return Err(MqError::Publish(format!(
673                        "topic '{}' is full: {} >= {} messages (H-3 protection)",
674                        topic, current_count, inner.max_messages_per_topic
675                    )));
676                }
677                OverflowStrategy::Block => {
678                    // Block 策略应由 publish_with_block 处理;若误入此路径则返回错误而非 panic
679                    return Err(MqError::Publish(format!(
680                        "topic '{}' overflow with Block strategy: use publish_with_block instead",
681                        topic
682                    )));
683                }
684            }
685        }
686        // 生成消息 ID 并插入
687        let id = format!("msg-{}", inner.next_id);
688        // L-2 修复:使用 checked_add 防止 u64 溢出
689        inner.next_id = inner
690            .next_id
691            .checked_add(1)
692            .ok_or_else(|| MqError::Publish("message id overflow: u64::MAX reached".to_string()))?;
693        let msg = Message {
694            id,
695            retry_count: 0,
696            ..Message::new(topic, message.to_vec())
697        };
698        inner
699            .queues
700            .entry(topic.to_string())
701            .or_insert_with(VecDeque::new)
702            .push_back(msg);
703        Ok(())
704    }
705
706    /// 阻塞模式 publish:队列满时等待,直到有空间
707    ///
708    /// 用于 Block 策略。使用 `tokio::sync::Notify` 实现等待/通知。
709    async fn publish_with_block(&self, topic: &str, message: &[u8]) -> Result<(), MqError> {
710        loop {
711            let notify = {
712                let mut inner = self.inner.write().await;
713                let current_count = inner.queues.get(topic).map(|q| q.len()).unwrap_or(0);
714                if current_count < inner.max_messages_per_topic {
715                    // 有空间,插入并返回
716                    let id = format!("msg-{}", inner.next_id);
717                    inner.next_id = inner.next_id.checked_add(1).ok_or_else(|| {
718                        MqError::Publish("message id overflow: u64::MAX reached".to_string())
719                    })?;
720                    let msg = Message {
721                        id,
722                        retry_count: 0,
723                        ..Message::new(topic, message.to_vec())
724                    };
725                    inner
726                        .queues
727                        .entry(topic.to_string())
728                        .or_insert_with(VecDeque::new)
729                        .push_back(msg);
730                    return Ok(());
731                }
732                // 队列满,获取 Notify 引用(按 topic 隔离)
733                inner
734                    .notify
735                    .entry(topic.to_string())
736                    .or_insert_with(|| Arc::new(Notify::new()))
737                    .clone()
738            };
739            // 释放写锁后等待通知(避免长时间持锁)
740            // Notify 内部使用 permit 机制,不会丢失通知
741            notify.notified().await;
742        }
743    }
744}
745
746// ============================================================================
747// QueueWrapper
748// ============================================================================
749
750pub struct QueueWrapper {
751    queue: Box<dyn MessageQueue>,
752    /// 重连策略(None 表示不重试,直接返回错误)
753    reconnect: Option<ReconnectPolicy>,
754}
755
756impl QueueWrapper {
757    pub fn new(provider: MqProvider) -> Self {
758        let queue: Box<dyn MessageQueue> = match provider {
759            MqProvider::Kafka(_) => Box::new(crate::kafka::InMemoryKafkaQueue::new()),
760            MqProvider::RabbitMQ(_) => Box::new(crate::rabbitmq::InMemoryRabbitmqQueue::new()),
761            MqProvider::RocketMQ(_) => Box::new(crate::rocketmq::InMemoryRocketmqQueue::new()),
762            MqProvider::ActiveMQ(_) => Box::new(crate::activemq::InMemoryActivemqQueue::new()),
763            MqProvider::Nats(_) => Box::new(crate::nats::InMemoryNatsQueue::new()),
764            MqProvider::Pulsar(_) => Box::new(crate::pulsar::InMemoryPulsarQueue::new()),
765        };
766        Self {
767            queue,
768            reconnect: None,
769        }
770    }
771
772    /// 从已有 queue 创建 wrapper(用于测试自定义 MessageQueue 实现)
773    #[cfg(test)]
774    pub(crate) fn with_queue(queue: Box<dyn MessageQueue>) -> Self {
775        Self {
776            queue,
777            reconnect: None,
778        }
779    }
780
781    /// 设置重连策略
782    ///
783    /// 启用后,`publish` / `consume` 在遇到 `MqError::Connection` 错误时
784    /// 会按指数退避策略自动重试,最多重试 `policy.max_retries` 次。
785    pub fn with_reconnect(mut self, policy: ReconnectPolicy) -> Self {
786        self.reconnect = Some(policy);
787        self
788    }
789
790    pub async fn publish(&self, topic: &str, message: &[u8]) -> Result<(), MqError> {
791        if let Some(policy) = &self.reconnect {
792            let mut attempts = 0u32;
793            loop {
794                match self.queue.publish(topic, message).await {
795                    Ok(()) => return Ok(()),
796                    Err(MqError::Connection(_)) if attempts < policy.max_retries => {
797                        let delay = policy.next_delay(attempts);
798                        tokio::time::sleep(delay).await;
799                        attempts += 1;
800                    }
801                    Err(e) => return Err(e),
802                }
803            }
804        } else {
805            self.queue.publish(topic, message).await
806        }
807    }
808
809    pub async fn consume(&self, topic: &str) -> Result<Option<Message>, MqError> {
810        if let Some(policy) = &self.reconnect {
811            let mut attempts = 0u32;
812            loop {
813                match self.queue.consume(topic).await {
814                    Ok(msg) => return Ok(msg),
815                    Err(MqError::Connection(_)) if attempts < policy.max_retries => {
816                        let delay = policy.next_delay(attempts);
817                        tokio::time::sleep(delay).await;
818                        attempts += 1;
819                    }
820                    Err(e) => return Err(e),
821                }
822            }
823        } else {
824            self.queue.consume(topic).await
825        }
826    }
827
828    pub async fn ack(&self, message_id: &str) -> Result<(), MqError> {
829        self.queue.ack(message_id).await
830    }
831
832    pub async fn subscribe(&self, topic: &str) -> Result<(), MqError> {
833        self.queue.subscribe(topic).await
834    }
835
836    /// 消息重回队列尾部(带重试次数追踪)
837    ///
838    /// 委托给底层 queue 的 nack 实现。重连策略不应用于 nack。
839    pub async fn nack(&self, message_id: &str) -> Result<(), MqError> {
840        self.queue.nack(message_id).await
841    }
842
843    /// 消息直接进入死信队列
844    ///
845    /// 委托给底层 queue 的 reject 实现。重连策略不应用于 reject。
846    pub async fn reject(&self, message_id: &str) -> Result<(), MqError> {
847        self.queue.reject(message_id).await
848    }
849}
850
851#[cfg(test)]
852mod tests {
853    use super::*;
854    use std::sync::atomic::{AtomicU32, Ordering};
855
856    // ========================================================================
857    // 既有测试(保持不变)
858    // ========================================================================
859
860    #[tokio::test]
861    async fn test_in_memory_queue_basic() {
862        let queue = InMemoryQueue::new();
863        queue.publish("topic1", b"hello").await.unwrap();
864        let msg = queue
865            .consume("topic1")
866            .await
867            .unwrap()
868            .expect("msg should exist");
869        assert_eq!(msg.payload, b"hello");
870        queue.ack(&msg.id).await.unwrap();
871    }
872
873    /// L-2 测试:next_id 溢出保护
874    #[tokio::test]
875    async fn test_l2_next_id_overflow_protection() {
876        let queue = InMemoryQueue::new();
877        {
878            let mut inner = queue.inner.write().await;
879            inner.next_id = u64::MAX;
880        }
881        let result = queue.publish("topic1", b"msg").await;
882        assert!(result.is_err());
883        match result {
884            Err(MqError::Publish(msg)) => {
885                assert!(
886                    msg.contains("overflow"),
887                    "expected overflow error, got: {}",
888                    msg
889                );
890            }
891            _ => panic!("Expected MqError::Publish with overflow message"),
892        }
893    }
894
895    /// L-2 测试:next_id 在 u64::MAX - 1 时仍可正常递增到 u64::MAX
896    #[tokio::test]
897    async fn test_l2_next_id_near_max() {
898        let queue = InMemoryQueue::new();
899        {
900            let mut inner = queue.inner.write().await;
901            inner.next_id = u64::MAX - 1;
902        }
903        let result1 = queue.publish("topic1", b"msg1").await;
904        assert!(result1.is_ok());
905        let result2 = queue.publish("topic1", b"msg2").await;
906        assert!(result2.is_err());
907    }
908
909    // ========================================================================
910    // nack / reject / 死信队列测试
911    // ========================================================================
912
913    /// nack 将消息重回队列尾部,并增加 retry_count
914    #[tokio::test]
915    async fn test_nack_requeues_message_with_retry_count() {
916        let queue = InMemoryQueue::new();
917        queue.publish("topic", b"msg1").await.unwrap();
918        let msg = queue.consume("topic").await.unwrap().unwrap();
919        assert_eq!(msg.retry_count, 0);
920
921        // nack 后消息重回队列
922        queue.nack(&msg.id).await.unwrap();
923        assert_eq!(queue.message_count("topic").await, 1);
924        assert_eq!(queue.in_flight_count().await, 0);
925
926        // 再次消费,retry_count 应为 1
927        let msg2 = queue.consume("topic").await.unwrap().unwrap();
928        assert_eq!(msg2.id, msg.id);
929        assert_eq!(msg2.retry_count, 1);
930    }
931
932    /// nack 多次后 retry_count 持续递增(未达上限前)
933    ///
934    /// 注意:consume 时看到的 retry_count 是上一次 nack 后的值(即本次 nack 之前的值)。
935    /// - 第 1 次 consume:retry_count = 0(刚 publish)
936    /// - nack → retry_count = 1,重回队列
937    /// - 第 2 次 consume:retry_count = 1
938    /// - nack → retry_count = 2,重回队列
939    /// - 以此类推
940    #[tokio::test]
941    async fn test_nack_increments_retry_count() {
942        let queue = InMemoryQueue::with_max_retries(10);
943        queue.publish("topic", b"data").await.unwrap();
944
945        for expected_retry in 0..5u32 {
946            let msg = queue.consume("topic").await.unwrap().unwrap();
947            assert_eq!(
948                msg.retry_count, expected_retry,
949                "consume should show retry_count before this iteration's nack"
950            );
951            queue.nack(&msg.id).await.unwrap();
952        }
953        // 消息仍在就绪队列中(未达 max_retries=10)
954        assert_eq!(queue.message_count("topic").await, 1);
955        assert_eq!(queue.dead_letter_count("topic").await, 0);
956    }
957
958    /// nack 达到 max_retries 后自动转入死信队列
959    #[tokio::test]
960    async fn test_nack_max_retries_sends_to_dlx() {
961        // max_retries = 3:第 3 次 nack 后转入 DLX
962        let queue = InMemoryQueue::with_max_retries(3);
963        queue.publish("topic", b"payload").await.unwrap();
964
965        // 第 1 次 nack:retry_count = 1,重回队列
966        let msg = queue.consume("topic").await.unwrap().unwrap();
967        queue.nack(&msg.id).await.unwrap();
968        assert_eq!(queue.message_count("topic").await, 1);
969        assert_eq!(queue.dead_letter_count("topic").await, 0);
970
971        // 第 2 次 nack:retry_count = 2,重回队列
972        let msg = queue.consume("topic").await.unwrap().unwrap();
973        assert_eq!(msg.retry_count, 1);
974        queue.nack(&msg.id).await.unwrap();
975        assert_eq!(queue.message_count("topic").await, 1);
976        assert_eq!(queue.dead_letter_count("topic").await, 0);
977
978        // 第 3 次 nack:retry_count = 3,达到 max_retries,转入 DLX
979        let msg = queue.consume("topic").await.unwrap().unwrap();
980        assert_eq!(msg.retry_count, 2);
981        queue.nack(&msg.id).await.unwrap();
982        assert_eq!(queue.message_count("topic").await, 0);
983        assert_eq!(queue.dead_letter_count("topic").await, 1);
984    }
985
986    /// max_retries = 0 时,第一次 nack 立即转入死信队列
987    #[tokio::test]
988    async fn test_nack_max_retries_zero_sends_to_dlx_immediately() {
989        let queue = InMemoryQueue::with_max_retries(0);
990        queue.publish("topic", b"msg").await.unwrap();
991        let msg = queue.consume("topic").await.unwrap().unwrap();
992        assert_eq!(msg.retry_count, 0);
993
994        // nack 后 retry_count 变为 1,1 >= 0 → 立即转入 DLX
995        queue.nack(&msg.id).await.unwrap();
996
997        assert_eq!(queue.message_count("topic").await, 0);
998        assert_eq!(queue.dead_letter_count("topic").await, 1);
999
1000        // 验证 DLX 中的消息 retry_count = 1
1001        let dlq_msg = queue
1002            .consume_dead_letter("topic")
1003            .await
1004            .expect("should have dead letter");
1005        assert_eq!(dlq_msg.retry_count, 1);
1006    }
1007
1008    /// nack 不存在的 message_id 返回错误
1009    #[tokio::test]
1010    async fn test_nack_unknown_message_id_returns_error() {
1011        let queue = InMemoryQueue::new();
1012        let result = queue.nack("nonexistent-id").await;
1013        assert!(result.is_err());
1014        match result {
1015            Err(MqError::NotSupported(msg)) => {
1016                assert!(msg.contains("not found for nack"));
1017            }
1018            _ => panic!("Expected MqError::NotSupported"),
1019        }
1020    }
1021
1022    /// reject 将消息直接送入死信队列
1023    #[tokio::test]
1024    async fn test_reject_sends_to_dead_letter_queue() {
1025        let queue = InMemoryQueue::new();
1026        queue.publish("topic", b"bad-msg").await.unwrap();
1027        let msg = queue.consume("topic").await.unwrap().unwrap();
1028
1029        queue.reject(&msg.id).await.unwrap();
1030
1031        assert_eq!(queue.message_count("topic").await, 0);
1032        assert_eq!(queue.in_flight_count().await, 0);
1033        assert_eq!(queue.dead_letter_count("topic").await, 1);
1034    }
1035
1036    /// reject 不增加 retry_count
1037    #[tokio::test]
1038    async fn test_reject_does_not_increment_retry_count() {
1039        let queue = InMemoryQueue::new();
1040        queue.publish("topic", b"msg").await.unwrap();
1041        let msg = queue.consume("topic").await.unwrap().unwrap();
1042        assert_eq!(msg.retry_count, 0);
1043
1044        queue.reject(&msg.id).await.unwrap();
1045
1046        let dlq_msg = queue
1047            .consume_dead_letter("topic")
1048            .await
1049            .expect("should have dead letter");
1050        assert_eq!(
1051            dlq_msg.retry_count, 0,
1052            "reject should not increment retry_count"
1053        );
1054    }
1055
1056    /// reject 不存在的 message_id 返回错误
1057    #[tokio::test]
1058    async fn test_reject_unknown_message_id_returns_error() {
1059        let queue = InMemoryQueue::new();
1060        let result = queue.reject("nonexistent-id").await;
1061        assert!(result.is_err());
1062    }
1063
1064    /// 空队列 reject 返回错误(in_flight 为空)
1065    #[tokio::test]
1066    async fn test_reject_empty_in_flight_returns_error() {
1067        let queue = InMemoryQueue::new();
1068        // 没有任何消息在 in_flight 中
1069        let result = queue.reject("any-id").await;
1070        assert!(result.is_err());
1071        assert_eq!(queue.dead_letter_count("topic").await, 0);
1072    }
1073
1074    /// dead_letter_count 对不存在的 topic 返回 0
1075    #[tokio::test]
1076    async fn test_dead_letter_count_empty_topic() {
1077        let queue = InMemoryQueue::new();
1078        assert_eq!(queue.dead_letter_count("no-such-topic").await, 0);
1079    }
1080
1081    /// dead_letter_count 在 reject 后正确计数
1082    #[tokio::test]
1083    async fn test_dead_letter_count_after_reject() {
1084        let queue = InMemoryQueue::new();
1085        queue.publish("topic", b"m1").await.unwrap();
1086        queue.publish("topic", b"m2").await.unwrap();
1087
1088        let m1 = queue.consume("topic").await.unwrap().unwrap();
1089        queue.reject(&m1.id).await.unwrap();
1090        assert_eq!(queue.dead_letter_count("topic").await, 1);
1091
1092        let m2 = queue.consume("topic").await.unwrap().unwrap();
1093        queue.reject(&m2.id).await.unwrap();
1094        assert_eq!(queue.dead_letter_count("topic").await, 2);
1095    }
1096
1097    /// consume_dead_letter 弹出最旧的死信消息
1098    #[tokio::test]
1099    async fn test_consume_dead_letter() {
1100        let queue = InMemoryQueue::new();
1101        queue.publish("topic", b"first").await.unwrap();
1102        queue.publish("topic", b"second").await.unwrap();
1103
1104        let m1 = queue.consume("topic").await.unwrap().unwrap();
1105        queue.reject(&m1.id).await.unwrap();
1106        let m2 = queue.consume("topic").await.unwrap().unwrap();
1107        queue.reject(&m2.id).await.unwrap();
1108
1109        // FIFO 顺序
1110        let d1 = queue
1111            .consume_dead_letter("topic")
1112            .await
1113            .expect("should have dead letter");
1114        assert_eq!(d1.payload, b"first");
1115        let d2 = queue
1116            .consume_dead_letter("topic")
1117            .await
1118            .expect("should have dead letter");
1119        assert_eq!(d2.payload, b"second");
1120
1121        // 死信队列已空
1122        assert!(queue.consume_dead_letter("topic").await.is_none());
1123    }
1124
1125    /// consume_dead_letter 对不存在的 topic 返回 None
1126    #[tokio::test]
1127    async fn test_consume_dead_letter_empty() {
1128        let queue = InMemoryQueue::new();
1129        assert!(queue.consume_dead_letter("no-such-topic").await.is_none());
1130    }
1131
1132    /// requeue_dead_letter 将死信消息放回原队列,并重置 retry_count
1133    #[tokio::test]
1134    async fn test_requeue_dead_letter_resets_retry_count() {
1135        let queue = InMemoryQueue::with_max_retries(2);
1136        queue.publish("topic", b"msg").await.unwrap();
1137
1138        // 第 1 次 nack:retry_count = 1,重回队列
1139        let m1 = queue.consume("topic").await.unwrap().unwrap();
1140        queue.nack(&m1.id).await.unwrap();
1141        // 第 2 次 nack:retry_count = 2,达到 max_retries=2,转入 DLX
1142        let m2 = queue.consume("topic").await.unwrap().unwrap();
1143        assert_eq!(m2.retry_count, 1);
1144        queue.nack(&m2.id).await.unwrap();
1145
1146        assert_eq!(queue.dead_letter_count("topic").await, 1);
1147        assert_eq!(queue.message_count("topic").await, 0);
1148
1149        // 重新入队,retry_count 应重置为 0
1150        queue.requeue_dead_letter(&m1.id).await.unwrap();
1151        assert_eq!(queue.dead_letter_count("topic").await, 0);
1152        assert_eq!(queue.message_count("topic").await, 1);
1153
1154        // 验证 retry_count 已重置
1155        let m3 = queue.consume("topic").await.unwrap().unwrap();
1156        assert_eq!(m3.id, m1.id);
1157        assert_eq!(
1158            m3.retry_count, 0,
1159            "retry_count should be reset after requeue"
1160        );
1161    }
1162
1163    /// requeue_dead_letter 对不存在的 message_id 返回错误
1164    #[tokio::test]
1165    async fn test_requeue_dead_letter_not_found() {
1166        let queue = InMemoryQueue::new();
1167        let result = queue.requeue_dead_letter("nonexistent-id").await;
1168        assert!(result.is_err());
1169        match result {
1170            Err(MqError::NotSupported(msg)) => {
1171                assert!(msg.contains("Dead letter not found"));
1172            }
1173            _ => panic!("Expected MqError::NotSupported"),
1174        }
1175    }
1176
1177    // ========================================================================
1178    // ReconnectPolicy 测试
1179    // ========================================================================
1180
1181    /// ReconnectPolicy 默认值
1182    #[test]
1183    fn test_reconnect_policy_default_values() {
1184        let policy = ReconnectPolicy::default();
1185        assert_eq!(policy.max_retries, 5);
1186        assert_eq!(policy.initial_delay_ms, 100);
1187        assert_eq!(policy.max_delay_ms, 10_000);
1188        assert!((policy.multiplier - 2.0).abs() < f64::EPSILON);
1189    }
1190
1191    /// ReconnectPolicy 指数退避计算
1192    #[test]
1193    fn test_reconnect_policy_next_delay_exponential() {
1194        let policy = ReconnectPolicy {
1195            max_retries: 5,
1196            initial_delay_ms: 100,
1197            max_delay_ms: 10_000,
1198            multiplier: 2.0,
1199        };
1200        // attempt 0: 100 * 2^0 = 100
1201        assert_eq!(policy.next_delay(0), Duration::from_millis(100));
1202        // attempt 1: 100 * 2^1 = 200
1203        assert_eq!(policy.next_delay(1), Duration::from_millis(200));
1204        // attempt 2: 100 * 2^2 = 400
1205        assert_eq!(policy.next_delay(2), Duration::from_millis(400));
1206        // attempt 3: 100 * 2^3 = 800
1207        assert_eq!(policy.next_delay(3), Duration::from_millis(800));
1208    }
1209
1210    /// ReconnectPolicy 延迟封顶 max_delay_ms
1211    #[test]
1212    fn test_reconnect_policy_next_delay_capped_at_max() {
1213        let policy = ReconnectPolicy {
1214            max_retries: 10,
1215            initial_delay_ms: 100,
1216            max_delay_ms: 1000,
1217            multiplier: 2.0,
1218        };
1219        // attempt 4: 100 * 2^4 = 1600 > 1000 → 封顶为 1000
1220        assert_eq!(policy.next_delay(4), Duration::from_millis(1000));
1221        // attempt 10: 同样封顶
1222        assert_eq!(policy.next_delay(10), Duration::from_millis(1000));
1223    }
1224
1225    /// ReconnectPolicy attempt = 0 返回 initial_delay_ms
1226    #[test]
1227    fn test_reconnect_policy_zero_attempt() {
1228        let policy = ReconnectPolicy {
1229            max_retries: 3,
1230            initial_delay_ms: 500,
1231            max_delay_ms: 10_000,
1232            multiplier: 3.0,
1233        };
1234        assert_eq!(policy.next_delay(0), Duration::from_millis(500));
1235    }
1236
1237    // ========================================================================
1238    // QueueWrapper 重连测试(使用 Mock 队列)
1239    // ========================================================================
1240
1241    /// 模拟连接错误的队列(用于测试重连)
1242    ///
1243    /// 在第 `succeed_on_attempt` 次调用 publish 时返回 Ok,之前返回 Connection 错误。
1244    struct FailingQueue {
1245        call_count: AtomicU32,
1246        succeed_on_attempt: u32,
1247    }
1248
1249    impl FailingQueue {
1250        fn new(succeed_on_attempt: u32) -> Self {
1251            Self {
1252                call_count: AtomicU32::new(0),
1253                succeed_on_attempt,
1254            }
1255        }
1256    }
1257
1258    #[async_trait]
1259    impl MessageQueue for FailingQueue {
1260        async fn publish(&self, _topic: &str, _message: &[u8]) -> Result<(), MqError> {
1261            let attempt = self.call_count.fetch_add(1, Ordering::SeqCst) + 1;
1262            if attempt >= self.succeed_on_attempt {
1263                Ok(())
1264            } else {
1265                Err(MqError::Connection(
1266                    "simulated connection error".to_string(),
1267                ))
1268            }
1269        }
1270
1271        async fn consume(&self, _topic: &str) -> Result<Option<Message>, MqError> {
1272            Err(MqError::Connection(
1273                "simulated connection error".to_string(),
1274            ))
1275        }
1276
1277        async fn ack(&self, _message_id: &str) -> Result<(), MqError> {
1278            Err(MqError::Connection("simulated".to_string()))
1279        }
1280
1281        async fn subscribe(&self, _topic: &str) -> Result<(), MqError> {
1282            Err(MqError::Connection("simulated".to_string()))
1283        }
1284    }
1285
1286    /// 模拟非连接错误的队列(用于测试不重试非连接错误)
1287    struct PublishErrorQueue;
1288
1289    #[async_trait]
1290    impl MessageQueue for PublishErrorQueue {
1291        async fn publish(&self, _topic: &str, _message: &[u8]) -> Result<(), MqError> {
1292            Err(MqError::Publish("non-connection error".to_string()))
1293        }
1294
1295        async fn consume(&self, _topic: &str) -> Result<Option<Message>, MqError> {
1296            Err(MqError::Publish("non-connection error".to_string()))
1297        }
1298
1299        async fn ack(&self, _message_id: &str) -> Result<(), MqError> {
1300            Ok(())
1301        }
1302
1303        async fn subscribe(&self, _topic: &str) -> Result<(), MqError> {
1304            Ok(())
1305        }
1306    }
1307
1308    /// 重连:在 Connection 错误时自动重试,最终成功
1309    #[tokio::test]
1310    async fn test_reconnect_retries_on_connection_error() {
1311        // 第 3 次调用成功(前 2 次失败)
1312        let failing = FailingQueue::new(3);
1313        let wrapper = QueueWrapper::with_queue(Box::new(failing)).with_reconnect(ReconnectPolicy {
1314            max_retries: 5,
1315            initial_delay_ms: 1, // 测试用短延迟
1316            max_delay_ms: 10,
1317            multiplier: 2.0,
1318        });
1319
1320        let result = wrapper.publish("topic", b"data").await;
1321        assert!(result.is_ok(), "should succeed after retries");
1322    }
1323
1324    /// 重连:达到 max_retries 后放弃,返回错误
1325    #[tokio::test]
1326    async fn test_reconnect_gives_up_after_max_retries() {
1327        // 永不成功
1328        let failing = FailingQueue::new(u32::MAX);
1329        let wrapper = QueueWrapper::with_queue(Box::new(failing)).with_reconnect(ReconnectPolicy {
1330            max_retries: 2,
1331            initial_delay_ms: 1,
1332            max_delay_ms: 10,
1333            multiplier: 2.0,
1334        });
1335
1336        let result = wrapper.publish("topic", b"data").await;
1337        assert!(result.is_err());
1338        match result {
1339            Err(MqError::Connection(_)) => {}
1340            _ => panic!("Expected MqError::Connection"),
1341        }
1342    }
1343
1344    /// 重连:非 Connection 错误不触发重试
1345    #[tokio::test]
1346    async fn test_reconnect_no_retry_on_non_connection_error() {
1347        let wrapper =
1348            QueueWrapper::with_queue(Box::new(PublishErrorQueue)).with_reconnect(ReconnectPolicy {
1349                max_retries: 5,
1350                initial_delay_ms: 1,
1351                max_delay_ms: 10,
1352                multiplier: 2.0,
1353            });
1354
1355        let result = wrapper.publish("topic", b"data").await;
1356        assert!(result.is_err());
1357        match result {
1358            Err(MqError::Publish(msg)) => {
1359                assert!(msg.contains("non-connection error"));
1360            }
1361            _ => panic!("Expected MqError::Publish"),
1362        }
1363    }
1364
1365    // ========================================================================
1366    // Backpressure 测试
1367    // ========================================================================
1368
1369    /// DropOldest 策略:队列满时丢弃最旧消息
1370    #[tokio::test]
1371    async fn test_backpressure_drop_oldest() {
1372        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1373            max_queue_size: 2,
1374            on_overflow: OverflowStrategy::DropOldest,
1375        });
1376
1377        queue.publish("topic", b"m1").await.unwrap();
1378        queue.publish("topic", b"m2").await.unwrap();
1379        // 队列已满(2 条),第 3 条触发 DropOldest:丢弃 m1,插入 m3
1380        queue.publish("topic", b"m3").await.unwrap();
1381
1382        assert_eq!(queue.message_count("topic").await, 2);
1383
1384        // 验证最旧消息 m1 已被丢弃
1385        let m1 = queue.consume("topic").await.unwrap().unwrap();
1386        assert_eq!(m1.payload, b"m2", "oldest should be dropped");
1387        let m2 = queue.consume("topic").await.unwrap().unwrap();
1388        assert_eq!(m2.payload, b"m3");
1389    }
1390
1391    /// DropNewest 策略:队列满时丢弃新消息(返回 Ok)
1392    #[tokio::test]
1393    async fn test_backpressure_drop_newest() {
1394        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1395            max_queue_size: 1,
1396            on_overflow: OverflowStrategy::DropNewest,
1397        });
1398
1399        queue.publish("topic", b"m1").await.unwrap();
1400        // 队列已满,第 2 条触发 DropNewest:丢弃 m2,返回 Ok
1401        let result = queue.publish("topic", b"m2").await;
1402        assert!(result.is_ok());
1403
1404        assert_eq!(queue.message_count("topic").await, 1);
1405        // 验证保留的是 m1(旧消息)
1406        let m = queue.consume("topic").await.unwrap().unwrap();
1407        assert_eq!(m.payload, b"m1", "newest should be dropped");
1408    }
1409
1410    /// Reject 策略:队列满时返回错误(与 H-3 行为一致)
1411    #[tokio::test]
1412    async fn test_backpressure_reject() {
1413        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1414            max_queue_size: 1,
1415            on_overflow: OverflowStrategy::Reject,
1416        });
1417
1418        queue.publish("topic", b"m1").await.unwrap();
1419        // 队列已满,第 2 条触发 Reject:返回错误
1420        let result = queue.publish("topic", b"m2").await;
1421        assert!(result.is_err());
1422
1423        assert_eq!(queue.message_count("topic").await, 1);
1424    }
1425
1426    /// Block 策略:队列满时阻塞,consume 后解除阻塞
1427    #[tokio::test]
1428    async fn test_backpressure_block_unblocks_on_consume() {
1429        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1430            max_queue_size: 1,
1431            on_overflow: OverflowStrategy::Block,
1432        });
1433        queue.publish("topic", b"m1").await.unwrap();
1434
1435        // 在另一个任务中尝试 publish(应阻塞)
1436        let queue_clone = queue.clone();
1437        let handle = tokio::spawn(async move { queue_clone.publish("topic", b"m2").await });
1438
1439        // 等待 50ms,确认任务仍在阻塞
1440        tokio::time::sleep(Duration::from_millis(50)).await;
1441        assert!(!handle.is_finished(), "publish should be blocked");
1442
1443        // consume 一条消息,释放空间
1444        queue.consume("topic").await.unwrap();
1445
1446        // 阻塞的 publish 应能完成
1447        let result = tokio::time::timeout(Duration::from_secs(1), handle)
1448            .await
1449            .expect("publish should complete after consume");
1450        assert!(result.is_ok(), "publish should succeed: {:?}", result);
1451
1452        // 验证 m2 已入队
1453        assert_eq!(queue.message_count("topic").await, 1);
1454        let m = queue.consume("topic").await.unwrap().unwrap();
1455        assert_eq!(m.payload, b"m2");
1456    }
1457
1458    /// Block 策略:队列持续满时,publish 在超时下保持阻塞
1459    #[tokio::test]
1460    async fn test_backpressure_block_times_out_when_queue_stays_full() {
1461        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1462            max_queue_size: 1,
1463            on_overflow: OverflowStrategy::Block,
1464        });
1465        queue.publish("topic", b"m1").await.unwrap();
1466
1467        // 尝试 publish,应阻塞;用 timeout 验证它不会立即返回
1468        let result =
1469            tokio::time::timeout(Duration::from_millis(100), queue.publish("topic", b"m2")).await;
1470
1471        // 应超时(队列持续满)
1472        assert!(result.is_err(), "publish should block and time out");
1473
1474        // 队列仍只有 1 条消息
1475        assert_eq!(queue.message_count("topic").await, 1);
1476    }
1477
1478    /// Block 策略:不同 topic 独立阻塞(互不影响)
1479    #[tokio::test]
1480    async fn test_backpressure_block_isolated_per_topic() {
1481        let queue = InMemoryQueue::with_backpressure(BackpressurePolicy {
1482            max_queue_size: 1,
1483            on_overflow: OverflowStrategy::Block,
1484        });
1485        queue.publish("topic-a", b"a1").await.unwrap();
1486        queue.publish("topic-b", b"b1").await.unwrap();
1487
1488        // topic-a 满,topic-b 满
1489        // 向 topic-a publish 应阻塞
1490        let queue_clone = queue.clone();
1491        let handle = tokio::spawn(async move { queue_clone.publish("topic-a", b"a2").await });
1492
1493        tokio::time::sleep(Duration::from_millis(50)).await;
1494        assert!(!handle.is_finished(), "topic-a publish should be blocked");
1495
1496        // consume topic-b 不应解除 topic-a 的阻塞
1497        queue.consume("topic-b").await.unwrap();
1498        tokio::time::sleep(Duration::from_millis(50)).await;
1499        assert!(
1500            !handle.is_finished(),
1501            "topic-a publish should still be blocked after topic-b consume"
1502        );
1503
1504        // consume topic-a 才能解除阻塞
1505        queue.consume("topic-a").await.unwrap();
1506        let result = tokio::time::timeout(Duration::from_secs(1), handle)
1507            .await
1508            .expect("publish should complete after topic-a consume");
1509        assert!(result.is_ok());
1510    }
1511}