|
|
# MQ
|
|
|
|
|
|
iTi-Flask 提供通用 MQ 入口。
|
|
|
v1 内置 Kafka backend,底层使用 `confluent-kafka`。
|
|
|
|
|
|
## 安装
|
|
|
|
|
|
Kafka 客户端是可选依赖:
|
|
|
|
|
|
```bash
|
|
|
uv add "iti-flask[mq-kafka]"
|
|
|
```
|
|
|
|
|
|
未启用 MQ 的项目不需要安装 Kafka 依赖。
|
|
|
|
|
|
## 配置
|
|
|
|
|
|
MQ 默认关闭。
|
|
|
|
|
|
```python
|
|
|
class DevConfig(BaseDevConfig):
|
|
|
def __init__(self) -> None:
|
|
|
super().__init__()
|
|
|
self.mq_enabled = True
|
|
|
self.mq = {
|
|
|
"backend": "kafka",
|
|
|
"bootstrap_servers": "127.0.0.1:9092",
|
|
|
"group_id": "my-app",
|
|
|
"client_id": "my-app-dev",
|
|
|
"auto_offset_reset": "earliest",
|
|
|
"failure_backoff_seconds": 1.0,
|
|
|
}
|
|
|
```
|
|
|
|
|
|
也可以使用环境变量:
|
|
|
|
|
|
```bash
|
|
|
MQ_ENABLED=true
|
|
|
MQ_BACKEND=kafka
|
|
|
KAFKA_BOOTSTRAP_SERVERS=127.0.0.1:9092
|
|
|
KAFKA_GROUP_ID=my-app
|
|
|
KAFKA_CLIENT_ID=my-app-dev
|
|
|
KAFKA_AUTO_OFFSET_RESET=earliest
|
|
|
MQ_FAILURE_BACKOFF_SECONDS=1
|
|
|
MQ_POLL_TIMEOUT_SECONDS=1
|
|
|
```
|
|
|
|
|
|
## 发送消息
|
|
|
|
|
|
```python
|
|
|
from iti.mq import mq_client
|
|
|
|
|
|
mq_client(app).send_json("mes.work_order.events", {"id": "MO001"}, key="MO001")
|
|
|
mq_client(app).send("raw.topic", value=b"bytes", key=b"k")
|
|
|
```
|
|
|
|
|
|
也可以先注册 producer:
|
|
|
|
|
|
```python
|
|
|
from iti.mq import mq_registry
|
|
|
|
|
|
mq_registry.register_producer(
|
|
|
name="work-order-events",
|
|
|
topic="mes.work_order.events",
|
|
|
)
|
|
|
|
|
|
mq_client(app).sender("work-order-events").send_json({"id": "MO001"})
|
|
|
```
|
|
|
|
|
|
## 监听消息
|
|
|
|
|
|
使用装饰器:
|
|
|
|
|
|
```python
|
|
|
from iti.mq import MQMessage, mq_consumer
|
|
|
|
|
|
|
|
|
@mq_consumer("mes.work_order.created", group_id="hsyh-mes")
|
|
|
async def handle_work_order(message: MQMessage) -> None:
|
|
|
payload = message.value
|
|
|
```
|
|
|
|
|
|
也可以显式注册:
|
|
|
|
|
|
```python
|
|
|
from iti.mq import mq_registry
|
|
|
|
|
|
|
|
|
def handle_work_order(message):
|
|
|
payload = message.value
|
|
|
|
|
|
|
|
|
mq_registry.register_consumer(
|
|
|
name="work-order-created",
|
|
|
topics=["mes.work_order.created"],
|
|
|
group_id="hsyh-mes",
|
|
|
handler=handle_work_order,
|
|
|
)
|
|
|
```
|
|
|
|
|
|
业务模块也可以在 `register_mq(app)` 阶段注册 consumer 和 producer。
|
|
|
|
|
|
## 消息格式
|
|
|
|
|
|
默认 `value_format="json"`。
|
|
|
框架用 UTF-8 JSON 解码 `message.value`,并保留 `message.raw_value`。
|
|
|
|
|
|
`value_format="bytes"` 时,`message.value` 是原始 bytes。
|
|
|
|
|
|
`MQMessage` 包含:
|
|
|
|
|
|
- `app`
|
|
|
- `topic`
|
|
|
- `partition`
|
|
|
- `offset`
|
|
|
- `key`
|
|
|
- `raw_key`
|
|
|
- `value`
|
|
|
- `raw_value`
|
|
|
- `headers`
|
|
|
- `timestamp`
|
|
|
- `raw_message`
|
|
|
|
|
|
## 消费语义
|
|
|
|
|
|
Kafka consumer 强制设置:
|
|
|
|
|
|
```python
|
|
|
enable.auto.commit = False
|
|
|
```
|
|
|
|
|
|
handler 正常结束后,框架同步提交当前消息 offset。
|
|
|
handler 抛错或 JSON 解码失败时,框架记录日志、不提交 offset、seek 回当前消息,并按 `failure_backoff_seconds` 等待后重试。
|
|
|
|
|
|
每个 consumer definition 启动一个线程,单线程顺序处理消息。
|
|
|
|
|
|
## 不支持
|
|
|
|
|
|
v1 不支持:
|
|
|
|
|
|
- DLQ。
|
|
|
- 批量消费。
|
|
|
- exactly-once 事务。
|
|
|
- 多 backend。
|
|
|
- Kafka topic 自动创建。
|