消息超时自动删除;队列层面和消息层面;

This commit is contained in:
bunny 2025-05-19 14:27:19 +08:00
parent c4cfca50a4
commit 7fdf76138e
7 changed files with 118 additions and 2 deletions

View File

@ -320,7 +320,7 @@ public void processQueue(String dataString, Message message, Channel channel) th
> | **手动ACK** (`AcknowledgeMode.MANUAL`) | ✔️ 推荐!保持 `unacked ≤ 5`ACK后立即补新消息 |
> | **自动ACK** (`AcknowledgeMode.AUTO`) | ⚠️ 无效消息投递后立即ACKprefetch无法限流 |
>
> >自动ACK模式下**prefetch仍然有效**限制未处理的消息数但消息会在投递后立即被ACK实际可能失去限流意义。
> >*自动ACK模式下**prefetch仍然有效**限制未处理的消息数但消息会在投递后立即被ACK实际可能失去限流意义。*
>
> **消费慢时的表现**
>
@ -359,4 +359,91 @@ public void processMessagePrefetch(String dataString, Channel channel, Message m
## 消息超时
![image-20250519135919549](./images/image-20250519135919549.png)
- 给消息设定一个过期时间,超过这个时间没有被取走的消息就会被删除,从两个层面来给消息设定过期时间。
- **队列层面:**在队列层面设定消息过期时间,并不是队列的过期时间。意思是这个队列中的消息全部使用同一个过期时间。
- **消息本身:**给具体的某个消息设定过期时间。
- 可通过两种方式设置消息TTLTime-To-Live那么哪个时间短哪个生效。
### 测试环境
测试时候不要用消费端消费(监听),监听取走了就不是超时了。
**创建交换机**
![image-20250519141236957](./images/image-20250519141236957.png)
**创建队列**
> [!NOTE]
> 过期时间单位为毫秒,如`5000`表示5秒。
创建交换机。直接点击下面的加粗字体可以直接设置。
**队列TTL设置步骤**
创建队列时在`Arguments`中添加:`x-message-ttl`: 设置值如5000
![image-20250519135919549](./images/image-20250519135919549.png)
**绑定交换机**
![image-20250519141220594](./images/image-20250519141220594.png)
### 测试队列层面
当在队列中设置了过期时间,超时后自动删除。
**测试Code**
```java
/* 测试过期时间 */
@Test
void buildExchangeTimeoutTest() {
String EXCHANGE = "exchange.test.timeout";
String QUEUE = "queue.test.timeout";
String ROUTING_KEY = "routing.key.test.timeout";
for (int i = 0; i < 100; i++) {
rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY, "测试消息超时时间【" + i + "】");
}
}
```
**测试效果**
![image-20250519141706027](./images/image-20250519141706027.png)
### 测试消息层面
> [!TIP]
>
> 和上面代码对比,区别在于,第四个参数是否设置了`MessagePostProcessor`。
>
> **队列TTL vs 消息TTL**
>
> - 队列TTL统一管理适合批量消息
> - 消息TTL灵活控制适合特殊消息
> [!IMPORTANT]
>
> **TTL过期后消息直接删除**(非进入死信队列,除非配置了`x-dead-letter-exchange`
```java
/* 测试过期时间---消息层面实现消息超时自动删除 */
@Test
void buildExchangeTimeoutTest2() {
String EXCHANGE = "exchange.test.timeout";
String QUEUE = "queue.test.timeout";
String ROUTING_KEY = "routing.key.test.timeout";
MessagePostProcessor postProcessor = message -> {
// 设置过期时间
message.getMessageProperties().setExpiration("7000");
return message;
};
for (int i = 0; i < 100; i++) {
rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY, "消息层面超时自动删除【" + i + "】", postProcessor);
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -4,6 +4,7 @@ import cn.bunny.mq.mqdemo.domain.RabbitMQMessageListenerConstants;
import cn.bunny.mq.mqdemo.domain.entity.Bunny;
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@ -56,4 +57,32 @@ class MqDemoApplicationTests {
rabbitTemplate.convertAndSend(exchangeDirect, routingKeyDirect, "测试消息发送【" + i + "");
}
}
/* 测试过期时间 */
@Test
void buildExchangeTimeoutTest1() {
String EXCHANGE = "exchange.test.timeout";
String ROUTING_KEY = "routing.key.test.timeout";
for (int i = 0; i < 100; i++) {
rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY, "测试消息超时时间【" + i + "");
}
}
/* 测试过期时间---消息层面实现消息超时自动删除 */
@Test
void buildExchangeTimeoutTest2() {
String EXCHANGE = "exchange.test.timeout";
String ROUTING_KEY = "routing.key.test.timeout";
MessagePostProcessor postProcessor = message -> {
// 设置过期时间
message.getMessageProperties().setExpiration("7000");
return message;
};
for (int i = 0; i < 100; i++) {
rabbitTemplate.convertAndSend(EXCHANGE, ROUTING_KEY, "消息层面超时自动删除【" + i + "", postProcessor);
}
}
}