nats

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 10, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package nats 提供 NATS 消息队列客户端封装。

基于 nats-io/nats.go,为 ekit 微服务提供统一的 NATS 接入。

核心特性

  • 自动重连 + 重连回调
  • Publish / Subscribe / QueueSubscribe
  • Request / Reply(同步 RPC 模式)
  • JSON 序列化/反序列化
  • 优雅关闭(drain)
  • JetStream:持久化消息 + 声明式流装配(EnsureStream,#122——流名/subjects/ 存储/容量缺省单源,CreateOrUpdateStream 语义 + 存量流冲突修复文案)

使用方式

// 连接
client, err := nats.NewClient("nats://localhost:4222",
    nats.WithName("my-service"),
    nats.WithReconnectWait(2*time.Second),
)
defer client.Close(context.Background()) // 0.x BREAKING(#83/#86):原无参 Close() 移除

// 发布
err := client.Publish(ctx, "order.created", []byte(`{"id":1}`))

// 订阅
sub, err := client.Subscribe(ctx, "order.created", func(msg *nats.Msg) {
    log.Printf("received: %s", string(msg.Data))
})
defer sub.Unsubscribe()

// Request/Reply
resp, err := client.Request(ctx, "user.get", []byte(`{"id":1}`), 5*time.Second)

Index

Constants

View Source
const (
	// DefaultStreamMaxAge 是 EnsureStream 的缺省消息保留时长。
	DefaultStreamMaxAge = 72 * time.Hour
	// DefaultStreamMaxBytes 是 EnsureStream 的缺省流字节上限(512 MB)。
	DefaultStreamMaxBytes = 512 << 20
)

家族缺省常量(#122):fuxi 三仓 310 行近同手搓的 stream 装配缺省值在此 单源化——某仓改 MaxAge 其余仓不跟随的漂移面就此收口。

Variables

This section is empty.

Functions

func QueueSubscribeJSON

func QueueSubscribeJSON[T any](c *Client, subject, queue string, handler func(ctx context.Context, msg *T)) (*nats.Subscription, error)

QueueSubscribeJSON 订阅主题(队列模式)并自动反序列化 JSON 消息。

同 SubscribeJSON,从 NATS message header 中提取 trace_id 注入 ctx。

func RequestJSON

func RequestJSON[Req, Resp any](ctx context.Context, c *Client, subject string, req *Req, timeout time.Duration) (*Resp, error)

RequestJSON 发送 JSON 请求并反序列化响应。 使用 context 控制超时和取消。 nil ctx 按 context.Background 处理(#101,与同文件 Publish 系列口径一致)。

⚠️ BREAKING(#88,0.x 阶段允许):ctx 由第二位移至首位,与 Request 及 Go「ctx 首参」惯例对齐——旧形态 RequestJSON[Req, Resp](c, ctx, ...) 与 同文件 Request(ctx, ...) 形态不一致,IDE 补全/人工誊写极易把 subject 传进 ctx 位。亦与 mq.Requester.RequestJSON 的接口形态一致。

func SubscribeJSON

func SubscribeJSON[T any](c *Client, subject string, handler func(ctx context.Context, msg *T)) (*nats.Subscription, error)

SubscribeJSON 订阅主题并自动反序列化 JSON 消息。

从 NATS message header 中提取 trace_id(如果存在)并注入到 handler 的 ctx, 保持分布式追踪在异步消息边界不断裂。Publisher 端需要在 Publish 时通过 PublishWithTraceID 注入 trace_id 才能形成完整链路。

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client 是 NATS 客户端封装。

func NewClient

func NewClient(urls string, opts ...NatsOption) (*Client, error)

NewClient 创建 NATS 客户端并连接。

urls 示例: "nats://localhost:4222" 或 "nats://host1:4222,nats://host2:4222"

func (*Client) Close

func (c *Client) Close(ctx context.Context) error

Close 关闭连接:发起 Drain 并等待「真正排空完成、连接进入 CLOSED」—— nats.go 的 Drain() 是异步的(立即返回,排空在内部 goroutine 里等所有订阅 的在途消息处理完),一个 handler 阻塞时排空会挂到库的 DrainTimeout(默认 30s)甚至更久(#83/#86),关停随之无界。现在 ctx 到期仍未排空就放弃等待、 回退 conn.Close() 强制关闭(连接关闭会让阻塞中的读/写尽快以错误收敛), 关停有界。Drain 被拒绝启动、而连接已被强制关闭(网络侧关闭、或重连窗口里 上游 Drain 自己关掉的)视为已达目标态,不算错误(#147)。

签名遵循矩阵硬规则「组件 Close 统一 Close(ctx) error + sync.Once 幂等」: 仅首次调用执行关闭动作并返回其结果,后续调用直接返回 nil。 nil ctx 按 context.Background() 处理(#79 口径)。

⚠️ BREAKING(0.x 允许):原无参 Close() 移除——Go 不支持同名方法重载, 无法按 issue #83 的设想保留无参兼容别名;调用点改为 c.Close(context.Background())。需要不等待排空的立即关闭,用 c.Conn().Close()。

func (*Client) Conn

func (c *Client) Conn() *nats.Conn

Conn 返回底层 nats.Conn(用于高级用法)。

func (*Client) ConnectedUrl

func (c *Client) ConnectedUrl() string

ConnectedUrl 返回当前连接的 URL。

func (*Client) Drain

func (c *Client) Drain() error

Drain 排空连接(等待所有消息处理完成后关闭)。

func (*Client) IsConnected

func (c *Client) IsConnected() bool

IsConnected 返回是否已连接。

func (*Client) NewJetStream

func (c *Client) NewJetStream() (*JetStream, error)

NewJetStream 创建 JetStream v2 客户端。

func (*Client) Publish

func (c *Client) Publish(ctx context.Context, subject string, data []byte) error

Publish 发布消息到指定主题。 nil ctx 按 context.Background 处理(#79,与同仓 WaitN/Acquire/DoValue 的兜底口径一致)。

func (*Client) PublishJSON

func (c *Client) PublishJSON(ctx context.Context, subject string, v any) error

PublishJSON 发布 JSON 编码的消息。 nil ctx 按 context.Background 处理(#79)。

func (*Client) PublishJSONWithTraceID

func (c *Client) PublishJSONWithTraceID(ctx context.Context, subject string, v any) error

PublishJSONWithTraceID 发布 JSON 消息并从 ctx 提取 trace_id 注入 NATS message header。 配合 SubscribeJSON 自动恢复 trace_id 形成跨消息链路的完整追踪。 nil ctx 按 context.Background 处理(#79)。

func (*Client) PublishWithTraceID

func (c *Client) PublishWithTraceID(ctx context.Context, subject string, data []byte) error

PublishWithTraceID 发布消息并从 ctx 提取 trace_id 注入 NATS message header。 配合 SubscribeJSON 自动恢复 trace_id 形成跨消息链路的完整追踪。 ctx 中无 trace_id 时退化为普通 Publish,行为向后兼容。 nil ctx 按 context.Background 处理(#79)。

func (*Client) QueueSubscribe

func (c *Client) QueueSubscribe(subject, queue string, handler func(*nats.Msg)) (*nats.Subscription, error)

QueueSubscribe 订阅主题(队列模式),同一队列组内只有一个消费者收到消息。 适用于负载均衡场景:多个服务实例订阅同一主题,消息只投递给其中一个。

handler 的 panic 同样就地收编(#145,见 safeMsgHandler)。

func (*Client) Reply

func (c *Client) Reply(subject string, handler func(msg *nats.Msg) []byte) (*nats.Subscription, error)

Reply 订阅主题并自动回复(用于实现 RPC 服务端)。 handler 的返回值会作为回复消息发送。

func (*Client) Request

func (c *Client) Request(ctx context.Context, subject string, data []byte, timeout time.Duration) (*nats.Msg, error)

Request 发送请求并等待回复。 使用 context 控制超时和取消。 nil ctx 按 context.Background 处理(#101,与同文件 Publish 系列的兜底 口径一致——同一份客户端对所有 API 容忍 nil ctx,不挑入口崩进程)。

func (*Client) Subscribe

func (c *Client) Subscribe(subject string, handler func(*nats.Msg)) (*nats.Subscription, error)

Subscribe 订阅主题,收到消息时调用 handler。 返回 Subscription,调用 Unsubscribe() 取消订阅。

handler 的 panic 被就地收编(#145):记 Error 日志、丢弃该条消息,订阅与 进程照常存活——外部不可信载荷引发的 panic 不得杀死整个进程。

type JetStream

type JetStream struct {
	// contains filtered or unexported fields
}

JetStream 是 NATS JetStream v2 API 客户端封装。 使用新的 jetstream 包,提供持久化消息、至少一次投递保证、流和消费者管理。

func (*JetStream) Consume

func (js *JetStream) Consume(ctx context.Context, stream, consumer string, handler jetstream.MessageHandler, opts ...jetstream.PullConsumeOpt) (jetstream.ConsumeContext, error)

Consume 消费消息(推模式,自动管理 ACK)。 返回 ConsumeContext,调用 Stop() 停止消费。

⚠️ ctx 只界「查/建消费者」阶段:上游 Consume 不收 ctx,消费一旦启动 **只由返回的 ConsumeContext 的 Stop()/Drain() 停止**(#103 文档化口径, SDK 限制)。nil ctx 按 context.Background 处理(#101)。

func (*JetStream) ConsumerInfo

func (js *JetStream) ConsumerInfo(ctx context.Context, stream, consumer string) (*jetstream.ConsumerInfo, error)

ConsumerInfo 获取消费者信息。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) CreateOrUpdateConsumer

func (js *JetStream) CreateOrUpdateConsumer(ctx context.Context, stream string, cfg jetstream.ConsumerConfig) (jetstream.Consumer, error)

CreateOrUpdateConsumer 创建或更新消费者。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) CreateStream

func (js *JetStream) CreateStream(ctx context.Context, name string, subjects ...string) error

CreateStream 创建流(如果不存在)。 仅在流确实不存在(ErrStreamNotFound)时创建; 瞬时错误原样返回,避免误判掩盖真实故障。 nil ctx 按 context.Background 处理(#101,与 Client 系列兜底口径一致)。

func (*JetStream) DeleteStream

func (js *JetStream) DeleteStream(ctx context.Context, name string) error

DeleteStream 删除流。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) EnsureStream added in v0.8.0

func (js *JetStream) EnsureStream(ctx context.Context, spec StreamSpec) (jetstream.Stream, error)

EnsureStream 声明式流装配(#122):确保一条业务流按 StreamSpec 存在—— 不存在则创建,已存在则按 spec 原地更新(上游 CreateOrUpdateStream 语义)。

与 CreateStream 的关系:CreateStream 是「仅当不存在时创建」的窄原语(流已 存在时不动配置、无缺省派生);EnsureStream 是声明式组合口——缺省派生 (流名/subjects/Storage/Retention/MaxAge/MaxBytes,见 StreamSpec)+ CreateOrUpdateStream + 存量流冲突修复文案,fuxi 三仓 310 行近同手搓的装配 知识在此单源。

WorkQueue 存量冲突:服务端对存量流的若干维度不可原地变更(retention 到/ 从 workqueue、storage 类型变更、sealed 流等)。此类错误会附「需手动删除后 重启」的修复文案——删除会丢弃未消费消息,先确认消费水位。新增/删除 subject 对 WorkQueue 存量流同样受限(部分版本服务端直接拒绝),冲突时同样按文案处置。

nil ctx 按 context.Background 处理(#101,与 JetStream 系列兜底口径一致)。

func (*JetStream) Fetch

func (js *JetStream) Fetch(ctx context.Context, stream, consumer string, batchSize int, opts ...jetstream.FetchOpt) (jetstream.MessageBatch, error)

Fetch 获取指定数量的消息(拉模式)。

ctx 界住**整个调用**(#103):既界消费者查找,也经 jetstream.FetchContext 注入取消息阶段——ctx 取消/到期时取消息立即终止,不再挂在 SDK 的 DefaultExpires(30s)上。delivery 阶段的取消原因经 batch.Error() 返回。

例外:调用方显式给 FetchMaxWait 时,上游禁止与 FetchContext 同用 (ErrInvalidOption),此时以显式超时为准回退无 ctx 形态(SDK 限制, 取消息阶段最多等 FetchMaxWait)——见 fetchWithContext。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) Messages

func (js *JetStream) Messages(ctx context.Context, stream, consumer string) (jetstream.MessagesContext, error)

Messages 创建消息迭代器(拉模式,持续消费)。

⚠️ ctx 只界「查/建消费者」阶段:上游 Messages 不收 ctx,迭代器一旦创建 只由返回的 MessagesContext 的 Stop()/Drain() 停止(#103 文档化口径, SDK 限制)。nil ctx 按 context.Background 处理(#101)。

func (*JetStream) Next

func (js *JetStream) Next(ctx context.Context, stream, consumer string, opts ...jetstream.FetchOpt) (jetstream.Msg, error)

Next 获取下一条消息(拉模式,阻塞直到超时)。

ctx 界住**整个调用**(#103):同 Fetch,经 jetstream.FetchContext 注入 取消息阶段,取消不再等 30s 过期。例外口径同 Fetch(FetchMaxWait 优先)。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) Publish

func (js *JetStream) Publish(ctx context.Context, subject string, data []byte, opts ...jetstream.PublishOpt) (*jetstream.PubAck, error)

Publish 发布消息到 JetStream 流。 nil ctx 按 context.Background 处理(#79,与 Client.Publish 口径一致)。

func (*JetStream) PublishAsync

func (js *JetStream) PublishAsync(subject string, data []byte, opts ...jetstream.PublishOpt) (jetstream.PubAckFuture, error)

PublishAsync 异步发布消息(批量发布,提高吞吐量)。

func (*JetStream) PublishAsyncComplete

func (js *JetStream) PublishAsyncComplete() <-chan struct{}

PublishAsyncComplete 等待所有异步发布完成。

func (*JetStream) PublishJSON

func (js *JetStream) PublishJSON(ctx context.Context, subject string, v any, opts ...jetstream.PublishOpt) (*jetstream.PubAck, error)

PublishJSON 发布 JSON 消息到 JetStream 流。 nil ctx 按 context.Background 处理(#79)。

func (*JetStream) Stream

func (js *JetStream) Stream(ctx context.Context, name string) (jetstream.Stream, error)

Stream 获取流。 nil ctx 按 context.Background 处理(#101)。

func (*JetStream) StreamInfo

func (js *JetStream) StreamInfo(ctx context.Context, stream string) (*jetstream.StreamInfo, error)

StreamInfo 获取流信息。 nil ctx 按 context.Background 处理(#101)。

type NatsOption

type NatsOption func(*options)

NatsOption 配置 Client 的可选参数。

func WithCloseHandler

func WithCloseHandler(fn func(conn *nats.Conn)) NatsOption

WithCloseHandler 设置连接关闭回调。

func WithDisconnectHandler

func WithDisconnectHandler(fn func(conn *nats.Conn, err error)) NatsOption

WithDisconnectHandler 设置断开连接回调。

func WithMaxReconnects

func WithMaxReconnects(n int) NatsOption

WithMaxReconnects 设置最大重连次数,-1 表示无限重连(默认)。

func WithName

func WithName(name string) NatsOption

WithName 设置客户端名称(用于 NATS 监控)。

func WithReconnectHandler

func WithReconnectHandler(fn func(conn *nats.Conn)) NatsOption

WithReconnectHandler 设置重连成功回调。

func WithReconnectWait

func WithReconnectWait(d time.Duration) NatsOption

WithReconnectWait 设置重连等待时间,默认 2 秒。

type StreamSpec added in v0.8.0

type StreamSpec struct {
	// Name 流名。空值时从客户端名(WithName)派生:非字母数字折叠为 '_'、
	// 统一大写、补 "_EVENTS" 后缀(fuxi-engine → FUXI_ENGINE_EVENTS,与
	// 三仓既成缺省同形)。客户端也未设 WithName 时显式报错——流名是持久化
	// 对象的主键,不静默兜底。
	Name string
	// Subjects 流的 subject 通配集。空值时取 Name+".>"(三仓一致的缺省形态)。
	Subjects []string
	// Storage 存储策略。零值取 FileStorage(三仓一致)。⚠ nats.go 的
	// MemoryStorage 与零值同为 0、无法与「未设置」区分——内存流不是本原语
	// 的目标场景,需要时直接用 CreateOrUpdateStream 传完整 StreamConfig。
	Storage jetstream.StorageType
	// Retention 保留策略。零值即 LimitsPolicy(与库缺省一致);显式
	// InterestPolicy / WorkQueuePolicy 直接生效。WorkQueue 存量流的不可原地
	// 更新冲突见 EnsureStream 的处置文案。
	Retention jetstream.RetentionPolicy
	// MaxAge 消息保留时长。零值取 DefaultStreamMaxAge。
	MaxAge time.Duration
	// MaxBytes 流字节上限。零值取 DefaultStreamMaxBytes;服务器原生「0=不限」
	// 的语义在本原语不可达(0 被解释为未设置),需要时用 CreateOrUpdateStream。
	MaxBytes int64
}

StreamSpec 是 EnsureStream 的声明式流规格(#122)。

零值字段一律取库缺省——消费方只写与缺省不同的字段;fuxi 三仓的近同手搓 (stream 名缺省、subjects 通配格式、Storage/Retention、MaxAge/MaxBytes) 逐字段收敛到 StreamConfig 的映射规则见各字段文档。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL