Beego 应用需在启动前全局初始化 NATS 连接并复用,不可在 Controller 中每次请求新建;必须启用 JetStream 并显式配置 stream 与 consumer 才能实现消息持久化。

Beego 本身不内置消息队列能力,整合 NATS 就是「在 Beego 应用里正确初始化并复用 nats.Conn」——不是给 Beego 加功能,而是让 Beego 的 Controller 或 Service 能安全调用 NATS 客户端。
为什么不能直接在 Controller 里 nats.Connect()
每次 HTTP 请求都新建连接会快速耗尽文件描述符,且 NATS 连接含 goroutine、网络缓冲、重连逻辑,不适合请求生命周期内创建销毁。
- Beego 的
Controller是短生命周期对象,defer nc.Close()会在请求结束时关闭连接,导致后续请求无法复用 - 未设超时和重试的
nats.Connect()在容器启动阶段若 NATS 暂不可达,Beego 应用直接 panic 或卡死在App.Run() - 多个 Controller 并发调用
nats.Connect()可能触发竞态,尤其当共用同一配置但没加锁时
如何在 Beego 中安全初始化 nats.Conn
必须在 Beego 启动前完成连接,并作为全局或单例注入。推荐在 main.go 的 init() 或 main() 函数中初始化,存入 beego.AppConfig 或自定义包变量。
- 用
nats.MaxReconnects(-1)和nats.ReconnectWait(2 * time.Second)避免启动失败,尤其在 Kubernetes 中 NATS Pod 可能晚于应用启动 - 生产环境必须传
nats.UserCredentials("./nats.creds")或nats.Token("xxx"),否则连接会被服务器拒绝,日志只显示authorization violation - URL 写成集群格式,如
"nats://nats-0:4222,nats://nats-1:4222",客户端自动负载均衡,别只写一个地址 - 连接成功后,建议用
nc.Flush()测试连通性,失败则os.Exit(1),避免静默降级
nc.Publish() 和 nc.Subscribe() 在 Beego 中的典型位置
发布(Publish)适合放在业务逻辑末尾,比如订单创建成功后通知下游;订阅(Subscribe)必须在应用启动时一次性注册,不能放 Controller 里——否则每次请求都重复订阅,造成消息被多次消费。
- 发布可封装进 service 层函数,例如
orderService.NotifyCreated(orderID string),内部调用nc.Publish("order.created", data) - 订阅应放在
main()中连接建立后,例如nc.Subscribe("inventory.deduct", handleDeduct),回调函数handleDeduct里再调用 Beego 的 model 或 service - 回调函数中禁止直接操作
this.Ctx或this.Data—— 它们属于 HTTP 请求上下文,而 NATS 回调是独立 goroutine - 若需写数据库,用
models.DeductStock(...)这类无上下文依赖的函数,别传*context.Context进去
容易被忽略的 JetStream 持久化开关
NATS 默认是“即发即忘”,重启后所有未消费消息丢失。Beego 做订单、支付等关键业务时,必须启用 JetStream 并显式指定 stream 和 consumer。
- 发布前先确保 stream 存在:
js, _ := nc.JetStream(); js.AddStream(&nats.StreamConfig{Name: "ORDERS", Subjects: []string{"order.>"}}) - 用
js.Publish()替代nc.Publish(),才能进持久化队列 - 订阅要用
js.SubscribeSync()或js.PullSubscribe(),普通nc.Subscribe()仍走内存通道 - JetStream 的 consumer 名称必须固定,否则重启后从头消费;建议用服务名 + 环境拼接,如
"order-service-prod"
最常漏掉的是:以为连上了 NATS 就自动持久化,结果压测时服务重启,几百条订单事件全丢。JetStream 不是默认开启的插件,是独立配置项,必须代码里显式调用 nc.JetStream() 并建 stream 才生效。


















