Files
VLoop/backend/internal/middleware/rabbitmq/rabbitMQ.go
yiyiis d8bca16362 fix: 拆分 RabbitMQ Channel,修复新视频不出现在推荐列表的问题
- RabbitMQ 结构体移除共享 Ch 字段,仅管理 Connection
- 每个MQ组件(Like/Comment/Social/Popularity/Timeline)持有独立 Channel
- Timeline Consumer 使用独立 Channel 并加入自动重连机制
- Redis 操作超时从 50ms 调整为 500ms,避免 NACK 循环
- router.go 中 notification 相关逻辑适配新 API
2026-05-22 23:57:06 +08:00

124 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package rabbitmq
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"feedsystem_video_go/internal/config"
"log"
"strconv"
"time"
amqp "github.com/rabbitmq/amqp091-go"
)
// RabbitMQ 只管理 ConnectionChannel 由各组件按需创建
type RabbitMQ struct {
Conn *amqp.Connection
}
func NewRabbitMQ(cfg *config.RabbitMQConfig) (*RabbitMQ, error) {
if cfg == nil {
return nil, errors.New("rabbitmq config is nil")
}
url := "amqp://" + cfg.Username + ":" + cfg.Password + "@" + cfg.Host + ":" + strconv.Itoa(cfg.Port) + "/"
conn, err := amqp.Dial(url)
if err != nil {
return nil, err
}
return &RabbitMQ{Conn: conn}, nil
}
func (r *RabbitMQ) Close() error {
if r == nil {
return nil
}
if r.Conn != nil {
return r.Conn.Close()
}
return nil
}
func (r *RabbitMQ) NewChannel() (*amqp.Channel, error) {
if r == nil || r.Conn == nil {
return nil, errors.New("rabbitmq connection is not initialized")
}
return r.Conn.Channel()
}
func DeclareTopic(ch *amqp.Channel, exchange string, queue string, bindingKey string) error {
if ch == nil {
return errors.New("channel is not initialized")
}
if exchange == "" || queue == "" || bindingKey == "" {
return errors.New("exchange/queue/bindingKey is required")
}
if err := ch.ExchangeDeclare(
exchange,
"topic",
true,
false,
false,
false,
nil,
); err != nil {
return err
}
q, err := ch.QueueDeclare(
queue,
true,
false,
false,
false,
amqp.Table{"x-dead-letter-exchange": DLXExchange},
)
if err != nil {
return err
}
if err := ch.QueueBind(
q.Name,
bindingKey,
exchange,
false,
nil,
); err != nil {
return err
}
if err := DeclareDLX(ch, queue); err != nil {
log.Printf("DLX declare failed for %s: %v", queue, err)
}
return nil
}
func PublishJSON(ctx context.Context, ch *amqp.Channel, exchange string, routingKey string, payload any) error {
if ch == nil {
return errors.New("channel is not initialized")
}
if exchange == "" || routingKey == "" {
return errors.New("exchange and routingKey are required")
}
b, err := json.Marshal(payload)
if err != nil {
return err
}
return ch.PublishWithContext(ctx, exchange, routingKey, false, false, amqp.Publishing{
ContentType: "application/json",
DeliveryMode: amqp.Persistent,
Timestamp: time.Now(),
Body: b,
})
}
func newEventID(n int) (string, error) {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}