package initialize
import (
"errors"
"fmt"
"github.com/nats-io/nats.go"
"go.uber.org/zap"
"nplusone/global"
"time"
)
func Nats() {
NatsURL := "nats://localhost:4222"
ServiceName := "LiaoRobotService"
conn, err := nats.Connect(NatsURL,
nats.Name(ServiceName),
nats.ReconnectWait(2*time.Second),
nats.MaxReconnects(10),
nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
global.GVA_LOG.Warn("nats已断开", zap.Error(err))
}),
nats.ReconnectHandler(func(nc *nats.Conn) {
global.GVA_LOG.Info("nats重新连接")
}),
nats.ClosedHandler(func(nc *nats.Conn) {
global.GVA_LOG.Info("nats连接关闭")
}),
)
if err != nil {
global.GVA_LOG.Error(fmt.Sprintf("连接nats失败: %v", err))
return
}
global.GVA_LOG.Info("nats服务已连接", zap.String("url", NatsURL))
global.GVA_NATS = conn
// 获取 JetStream 连接对象
js, err := conn.JetStream()
if err != nil {
global.GVA_LOG.Error("获取 JetStream 连接失败,可能 NATS 服务未启用 JetStream (--js)", zap.Error(err))
return
}
createPushConsumer(js)
global.GVA_JETSTREAM = js
global.GVA_Subscription = make(map[string]*nats.Subscription)
}
// 创建Push模式的消费者
// 创建Push模式的Durable消费者
func createPushConsumer(js nats.JetStreamContext) {
// 检查消费者是否已存在
StreamName := "InspectionRobotStream"
ConsumerName := "inspection-robot-consumer-test02"
_, err := js.ConsumerInfo(StreamName, ConsumerName)
if err == nil {
global.GVA_LOG.Info("消费者已存在", zap.String("consumer", ConsumerName))
err := js.DeleteConsumer(StreamName, ConsumerName)
if err != nil {
global.GVA_LOG.Error("删除消费者失败", zap.Error(err))
}
}
// 消费者配置(Push模式核心参数)
consumerCfg := &nats.ConsumerConfig{
Durable: ConsumerName, // 持久化名称(关键)
AckPolicy: nats.AckExplicitPolicy, // 手动确认(必须)
DeliverPolicy: nats.DeliverNewPolicy, // 只接收新消息
MaxAckPending: 100, // 未确认消息的最大数量(Push模式推荐设置)
AckWait: 30 * time.Second, // 等待确认的超时时间
MaxDeliver: 5, // 消息最大投递次数
FilterSubject: "inspection.*", // 只消费特定主题(可选,更精确的过滤)
DeliverSubject: "inspection.*",
}
// 创建消费者
_, err = js.AddConsumer(StreamName, consumerCfg)
if err != nil {
if errors.Is(err, nats.ErrConsumerNameAlreadyInUse) {
global.GVA_LOG.Info("消费者已存在,无需创建", zap.String("consumer", ConsumerName))
}
global.GVA_LOG.Info("添加消费者失败", zap.Error(err))
}
global.GVA_LOG.Info("Push模式消费者创建成功", zap.String("consumer", ConsumerName))
}
和
func (c *natsClient) SubscribeJetStream() error {
subject := "InspectionRobot.JetStreamTest"
consumerName := "inspection-robot-consumer-test"
streamName := "InspectionRobotStream"
// 1. 创建或绑定Durable消费者
sub, err := global.GVA_JETSTREAM.Subscribe(subject, func(msg *nats.Msg) {
global.GVA_LOG.Info("收到JetStream消息",
zap.String("subject", msg.Subject),
zap.String("reply", msg.Reply),
zap.String("data", string(msg.Data)))
// 处理消息
// 确认消息
if err := msg.Ack(); err != nil {
global.GVA_LOG.Error("消息确认失败",
zap.String("subject", msg.Subject),
zap.Error(err))
}
},
nats.Bind(streamName, consumerName), // 绑定到流和消费者
nats.ManualAck(), // 手动确认模式
//nats.DeliverNew(), // 只接收新消息
nats.AckWait(30*time.Second), // 设置ACK等待时间
)
if err != nil {
global.GVA_LOG.Error("订阅JetStream失败",
zap.String("subject", subject),
zap.Error(err))
return fmt.Errorf("订阅JetStream失败: %w", err)
}
// 保存订阅对象
c.mu.Lock()
defer c.mu.Unlock()
if c.subscriptions == nil {
c.subscriptions = make(map[string]*nats.Subscription)
}
c.subscriptions["inspection_robot"] = sub
global.GVA_LOG.Info("成功订阅JetStream主题",
zap.String("subject", subject),
zap.String("consumer", consumerName))
return nil
}
你告诉我,我现在想要使用push消费者,我这些代码哪里写错了,为什么会报错nats: must use pull subscribe to bind to pull based consumer呢?指出错误原因
最新发布