fix: 拆分 RabbitMQ Channel,修复新视频不出现在推荐列表的问题
- RabbitMQ 结构体移除共享 Ch 字段,仅管理 Connection - 每个MQ组件(Like/Comment/Social/Popularity/Timeline)持有独立 Channel - Timeline Consumer 使用独立 Channel 并加入自动重连机制 - Redis 操作超时从 50ms 调整为 500ms,避免 NACK 循环 - router.go 中 notification 相关逻辑适配新 API
This commit is contained in:
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"feedsystem_video_go/internal/middleware/rabbitmq"
|
||||
"feedsystem_video_go/internal/middleware/redis"
|
||||
rediscache "feedsystem_video_go/internal/middleware/redis"
|
||||
"feedsystem_video_go/internal/video"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
func StartOutboxPoller(db *gorm.DB, tmq *rabbitmq.TimelineMQ) {
|
||||
if db == nil || tmq == nil || tmq.RabbitMQ == nil || tmq.Ch == nil {
|
||||
if db == nil || tmq == nil {
|
||||
log.Printf("Outbox poller disabled: timeline mq is not initialized")
|
||||
return
|
||||
}
|
||||
@@ -46,9 +46,9 @@ func StartOutboxPoller(db *gorm.DB, tmq *rabbitmq.TimelineMQ) {
|
||||
}()
|
||||
}
|
||||
|
||||
func StartConsumer(tmq *rabbitmq.TimelineMQ, queueName string, redisClient *redis.Client) {
|
||||
if tmq == nil || tmq.RabbitMQ == nil || tmq.Ch == nil {
|
||||
log.Printf("Timeline consumer disabled: timeline mq is not initialized")
|
||||
func StartConsumer(tmq *rabbitmq.TimelineMQ, queueName string, redisClient *rediscache.Client, rmq *rabbitmq.RabbitMQ) {
|
||||
if tmq == nil || rmq == nil || rmq.Conn == nil {
|
||||
log.Printf("Timeline consumer disabled: rabbitmq is not initialized")
|
||||
return
|
||||
}
|
||||
if redisClient == nil {
|
||||
@@ -56,54 +56,64 @@ func StartConsumer(tmq *rabbitmq.TimelineMQ, queueName string, redisClient *redi
|
||||
return
|
||||
}
|
||||
|
||||
msgs, err := tmq.Ch.Consume(
|
||||
queueName,
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("注册消费失败")
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
for msg := range msgs {
|
||||
var event rabbitmq.TimelineEvent
|
||||
err := json.Unmarshal(msg.Body, &event)
|
||||
|
||||
for {
|
||||
// 每次重连创建独立的 Channel,不与发布者共用
|
||||
ch, err := rmq.NewChannel()
|
||||
if err != nil {
|
||||
log.Printf("反序列化失败")
|
||||
log.Printf("Timeline consumer: 创建 Channel 失败: %v, 5秒后重试", err)
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := ch.Qos(10, 0, false); err != nil {
|
||||
log.Printf("Timeline consumer: QoS 设置失败: %v", err)
|
||||
}
|
||||
|
||||
msgs, err := ch.Consume(queueName, "", false, false, false, false, nil)
|
||||
if err != nil {
|
||||
log.Printf("Timeline consumer: 注册消费失败: %v, 5秒后重试", err)
|
||||
ch.Close()
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("Timeline consumer 已启动, queue=%s", queueName)
|
||||
|
||||
for msg := range msgs {
|
||||
var event rabbitmq.TimelineEvent
|
||||
if err := json.Unmarshal(msg.Body, &event); err != nil {
|
||||
log.Printf("Timeline consumer: 反序列化失败: %v", err)
|
||||
msg.Ack(false)
|
||||
continue
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
timelineKey := redisClient.Key("feed:global_timeline")
|
||||
err = redisClient.ZAdd(ctx, timelineKey, oredis.Z{
|
||||
Score: float64(event.CreateTime),
|
||||
Member: fmt.Sprintf("%d", event.VideoID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Timeline consumer: 写入Zset失败: %v", err)
|
||||
msg.Nack(false, true)
|
||||
cancel()
|
||||
continue
|
||||
}
|
||||
|
||||
if err := redisClient.ZRemRangeByRank(ctx, timelineKey, 0, -1001); err != nil {
|
||||
log.Printf("Timeline consumer: ZRem失败: %v", err)
|
||||
}
|
||||
|
||||
msg.Ack(false)
|
||||
continue
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
timelineKey := redisClient.Key("feed:global_timeline")
|
||||
err = redisClient.ZAdd(ctx, timelineKey, oredis.Z{
|
||||
Score: float64(event.CreateTime),
|
||||
Member: fmt.Sprintf("%d", event.VideoID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Printf("写入Zset失败")
|
||||
msg.Nack(false, true)
|
||||
cancel()
|
||||
continue
|
||||
}
|
||||
|
||||
err = redisClient.ZRemRangeByRank(ctx, timelineKey, 0, -1001)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("ZRem失败")
|
||||
}
|
||||
|
||||
msg.Ack(false)
|
||||
cancel()
|
||||
// msgs channel 关闭说明 AMQP Channel 断开,关闭并重连
|
||||
ch.Close()
|
||||
log.Printf("Timeline consumer: Channel 断开, 5秒后重连...")
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user