client

package
v0.8.0 Latest Latest
Warning

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

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

Documentation

Overview

Package client 提供 NNS(enjoydream Naming Service)治理核心: 服务发现、配置管理、实例订阅与注册的 provider 无关实现。

ServiceClient 不耦合任何注册中心 SDK:Registrar/Discoverer/Subscriber/ ConfigStore 经 With* 选项注入,未注入时处于降级态(mock/静态实例/缓存兜底)。 Nacos 默认构造由 nns 根门面(nns.New)承担——门面是 provider 选择点。 每次调用 New 返回独立实例(v0.15.2 起无包级单例)。

能力一览:

  • 实例发现带多级降级链(短路静态 → mock → 新鲜缓存 → singleflight Discover → stale 缓存兜底 → 兜底静态实例),provider 抖动不断服务; 降级序可配置(WithFallbackOrder / WithStaticFallback),支持 「注册中心优先、静态地址兜底」的生产形态
  • 多服务名注册:RegisterAs / DeregisterAs 让同一 SDK 连接注册多个端点名
  • 配置热更新(WatchService / OnConfigChange),超时/重试/LB 策略 等运行时生效
  • Close 为终结操作:注销监听与订阅、关闭默认路径创建的 SDK 客户端, 幂等;复用需重新 New

该包被 nns/kitex、nns/hertz、nns/endpoint 适配层消费,将完整降级链 桥接到各框架的服务发现接口。

Index

Constants

This section is empty.

Variables

View Source
var ErrClientClosed = errors.New("nns: client closed")

ErrClientClosed 在 ServiceClient.Close() 之后调用订阅类方法时返回。 Close 是终结操作(v0.28.0 起),复用需重新 New。

View Source
var ErrConfigStoreUnavailable = errors.New("nns: config store not available")

ErrConfigStoreUnavailable 在需要真实配置拉取的入口(ServiceConfig)被调、 但未注入 ConfigStore(mock 模式之外)时返回(#77)。

View Source
var ErrRegistrarUnavailable = errors.New("nns: registrar not available")

ErrRegistrarUnavailable 历史上在 ServiceClient.Register 被调用但未配置 registrar 时返回。常见场景:未注入 registrar、Mock 模式未启用、provider 构造失败降级。

#66 起「没注册器」改为幂等 no-op success,本哨兵**不再被任何入口返回** (全仓零返回点),仅为兼容保留符号:消费方照旧编译不报错,但 errors.Is(err, ErrRegistrarUnavailable) 分支永不命中,不应再写依赖它的 错误分叉(判「没注册器」请直接看 MockMode()/Registrar())。

View Source
var ErrServiceNameRequired = errors.New("nns: service name required")

ErrServiceNameRequired 在显式指定服务名的注册/注销入口(RegisterAs / DeregisterAs)拿到空服务名时返回。

Functions

This section is empty.

Types

type ClientOption

type ClientOption func(*ServiceClient)

ClientOption ServiceClient 的配置选项函数类型。

func WithCacheExpiry

func WithCacheExpiry(d time.Duration) ClientOption

WithCacheExpiry 设置实例缓存的过期时间。

d <= 0(含零值缺省)时回退 defaultCacheExpiry(30s,与门面 nns.New 同缺省): 零值不表示「禁用过期检查」——容错层没有「永不过期」语义,注册中心故障时 的新鲜缓存兜底(Discover 链第 3 级)依赖正常的过期判定(nns#94)。

func WithConfigGroup

func WithConfigGroup(group string) ClientOption

WithConfigGroup 设置配置读取的分组(默认 provider 配置里的 group 概念, 本包只把它当不透明字符串透传给 ConfigStore)。

func WithConfigStore

func WithConfigStore(s registry.ConfigStore) ClientOption

WithConfigStore 注入自定义的配置存储(用于测试或替换 provider)。

func WithDiscoverer

func WithDiscoverer(d registry.Discoverer) ClientOption

WithDiscoverer 注入自定义的服务发现器(用于测试或替换 provider)。

func WithFallbackOrder added in v0.5.0

func WithFallbackOrder(order FallbackOrder) ClientOption

WithFallbackOrder 设置全局降级序:静态实例与注册中心谁优先。

缺省为 FallbackStaticFirst(静态实例短路注册中心,与既有行为一致)。 设为 FallbackRegistryFirst 后,全部服务的静态实例降级为「兜底」: 注册中心路径失败或返回空时才参与取值。

单服务可用 WithStaticFallback 单独指定兜底语义,不受全局序影响。

func WithLocalServiceConfig

func WithLocalServiceConfig(serviceName string, basic *metadata.ServiceBasic) ClientOption

WithLocalServiceConfig 配置本地服务配置(不从 Nacos 获取) 用于本地开发或测试环境,直接指定服务的超时、重试等配置

func WithMockMode

func WithMockMode(enabled bool) ClientOption

WithMockMode 设置是否启用 Mock 模式,Mock 模式下不连接 Nacos。

func WithRegistrar

func WithRegistrar(r registry.Registrar) ClientOption

WithRegistrar 注入自定义的服务注册器(用于测试或替换 provider)。

func WithStaticFallback added in v0.5.0

func WithStaticFallback(serviceName string, instances []registry.Instance) ClientOption

WithStaticFallback 配置指定服务的**兜底**静态实例。

与 WithStaticInstances 的区别只在参与时机:

  • WithStaticInstances:短路静态——配了就直接返回,注册中心不被查询;
  • WithStaticFallback:兜底静态——只有注册中心路径失败或返回空时才返回它。

典型用法是生产形态的「注册中心优先、静态地址兜底」:静态地址 (如 k8s Service DNS)与注册中心同时配置,注册中心有健康实例时以 注册中心为准(静态地址在实例换 IP 后不会跟着变),注册中心冷启动或 故障时才用静态地址兜底。

同一服务上重复配置以最后一次调用为准:WithStaticFallback 与 WithStaticInstances 写同一份静态实例表,前者把该服务标记为兜底语义。

权重与注册侧同口径:Weight<=0(漏配或显式 0)回填默认权重 10, 显式正权重原样保留——见 normalizeStaticInstances。

func WithStaticInstances

func WithStaticInstances(serviceName string, instances []registry.Instance) ClientOption

WithStaticInstances 配置指定服务的静态实例列表,用于本地开发或特殊场景。

默认是**短路**语义:配了该服务的静态实例后,GetInstances 直接返回它们, 不再查询注册中心。需要「注册中心优先、静态地址兜底」的生产形态请用 WithStaticFallback(或全局 WithFallbackOrder(FallbackRegistryFirst))。

同一服务上与 WithStaticFallback 重复配置时以最后一次调用为准——本选项把 该服务恢复为短路语义。

权重与注册侧同口径:Weight<=0(漏配或显式 0)回填默认权重 10, 显式正权重原样保留——见 normalizeStaticInstances。

func WithSubscriber

func WithSubscriber(s registry.Subscriber) ClientOption

WithSubscriber 注入自定义的服务订阅器(用于测试或替换 provider)。

type ConfigChangeHandle added in v0.8.0

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

ConfigChangeHandle 是 OnConfigChange 注册配置变更回调的注销句柄。

Go 函数值不可比较,无法按函数身份摘除——注册条目以指针包装存储, 调用方保存 OnConfigChange 返回的句柄、传给 OffConfigChange 即可精确 注销该次注册(与 instanceCallback 的指针包装同一口径)。零值句柄与 重复注销均为 no-op。

典型生命周期:组件(如 endpoint factory)构造时注册、Close 时注销—— 否则长生命周期的 ServiceClient 会经回调闭包持续持有已废弃的组件。

type FallbackOrder added in v0.5.0

type FallbackOrder int

FallbackOrder 决定静态实例与注册中心的取值优先序。

静态实例有两种角色,差别只在「什么时候参与取值」:

  • 短路静态(WithStaticInstances,FallbackStaticFirst 下的默认):为服务 配了静态实例就直接返回,不再查询注册中心。适合本地开发、测试。
  • 兜底静态(WithStaticFallback,或全局 FallbackRegistryFirst 下的 静态实例):先查注册中心,注册中心路径失败或返回空时才用静态实例 兜底。适合生产形态——静态地址(如 k8s Service DNS)只是最后一层, 注册中心有健康实例时以注册中心为准。
const (
	// FallbackStaticFirst 静态实例优先(默认):配了静态实例就短路注册中心。
	//
	// 保持既有行为不变:已按短路语义配置静态实例的调用方不受影响。
	FallbackStaticFirst FallbackOrder = iota

	// FallbackRegistryFirst 注册中心优先:先查注册中心,注册中心路径失败
	// 或返回空时才用静态实例兜底。
	//
	// 适用于「注册中心优先、静态地址兜底」的生产形态:注册中心有健康
	// 实例时不再被静态地址遮蔽(静态地址在实例换 IP 后不会跟着变),
	// 而注册中心冷启动、故障且缓存为空时仍有兜底可用。
	FallbackRegistryFirst
)

func (FallbackOrder) String added in v0.5.0

func (o FallbackOrder) String() string

String 返回降级序的可读名称。

type ServiceClient

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

ServiceClient NNS 服务核心客户端,管理服务发现、配置、实例缓存和订阅。

依赖 registry 包定义的 4 个接口(Registrar/Discoverer/Subscriber/ConfigStore), 不直接耦合任何具体注册中心 SDK:provider 经 With* 选项注入,未注入即 降级态(mock/静态实例/缓存兜底);Nacos 默认构造由 nns 根门面承担。

func New

func New(opts ...ClientOption) *ServiceClient

New 创建一个独立的 ServiceClient 实例(provider 无关)。

每次调用都返回全新实例,互不影响。本包不绑定任何注册中心 provider: 通过 WithRegistrar/WithDiscoverer/WithSubscriber/WithConfigStore 注入 实现(如 mock 或替代 provider)。未注入任何接口且未开 Mock 时保持 降级态(namingAvailable()==false,走缓存/静态实例路径)——Nacos 默认 构造由 nns 门面负责(门面是 provider 选择点),见 nns.New。

func (*ServiceClient) AddStaticFallback added in v0.6.0

func (c *ServiceClient) AddStaticFallback(serviceName string, instances ...registry.Instance)

AddStaticFallback 追加**兜底**静态实例(与 WithStaticFallback 一致的语义)。

与 AddStaticInstance 的区别只在参与时机:本入口把该服务标记为兜底语义, **不改变发现路径**——注册中心仍是第一数据源,只有注册中心路径失败或返回 空时静态实例才参与取值。运行期热加备用地址(管理面/脚本)用它,不会切断 注册中心发现(#128)。

权重与注册侧同口径:Weight<=0 回填默认权重 10(见 normalizeStaticInstances)。

func (*ServiceClient) AddStaticInstance

func (c *ServiceClient) AddStaticInstance(serviceName string, instances ...registry.Instance)

AddStaticInstance 添加静态服务实例(**短路**语义,与 WithStaticInstances 一致)。

⚠️ 会改变发现路径(#128):FallbackStaticFirst(缺省)下,此前没有静态 配置的服务被写入后即**短路注册中心**——实例上下线、权重调整、健康摘除 不再反映到 GetInstances/GetAllInstances。运行期热加「备用地址」请改用 AddStaticFallback(兜底语义,注册中心发现保持不变);确要切到短路时本 函数会打 Warn 点明后果。已有语义标记跟随(fallbackOnly 不被改写): 兜底语义的服务追加实例仍是兜底。

权重与注册侧同口径:Weight<=0 回填默认权重 10(见 normalizeStaticInstances)。

func (*ServiceClient) BindServiceBasic

func (c *ServiceClient) BindServiceBasic(serviceName string, basic *metadata.ServiceBasic)

BindServiceBasic 解析服务全名并设置服务基本配置的默认值。

只对**未配置**(<=0)的超时回填默认值(ConnTimeout 1000ms / ReadTimeout 5000ms / WriteTimeout 5000ms);显式配置的取值原样保留——1–49ms 的低延迟 超时不再被改写成默认值(#127:此前 <50 一律静默钳成 1000/5000ms,20ms 的配置被吞 50 倍且零日志),仅打 Warn 防呆、不改写。

Retry:负值钳 0(负重试无意义;这是仅存的改写,必留日志);>15 原样保留 并 Warn——不再静默钳 15(#127)。

本函数是配置消费的必经点(LocalServiceInit / LoadDepService / ServiceConfig / ServiceWithName / WatchService 热更回调),口径统一在 这里收口:配置中心原文与生效值一致。

func (*ServiceClient) Close

func (c *ServiceClient) Close()

Close 释放 ServiceClient 持有的资源(幂等)。 停止所有配置监听、注销实例订阅、清空回调状态,最后关闭默认路径创建的 Nacos SDK 客户端(各持 gRPC 长连接 + 后台 goroutine)。 保证 Close 后实例可安全重建(重新 WatchService/OnConfigChange 不残留旧状态)。

func (*ServiceClient) CloseWithContext added in v0.5.1

func (c *ServiceClient) CloseWithContext(ctx context.Context) error

CloseWithContext 关闭并返回错误(ctx 有界)。

与 Close 的差别只有两点:

  • **ctx 有界**:Close 内部原先用 context.Background() 调 SDK 的 Unsubscribe / StopListenConfig ⇒ SDK 不响应时 Close **永久挂住** (调用方无从得知卡在哪一步)。这里把 ctx 透传给调用方;Close 走 默认 5s 上限(见 closeDefaultTimeout)。
  • **错误不吞**:注销订阅 / 停止配置监听的失败原样返回(Close 入口仍 只记日志——它没有返回值可给)。

幂等:与 Close 共享同一个 sync.Once,重复调用只有第一次真正执行。

func (*ServiceClient) Deregister

func (c *ServiceClient) Deregister(ctx context.Context, port int, opts ...registry.RegisterOptionFunc) error

Deregister 从注册中心注销当前服务实例。

实例身份优先取 Register 成功时缓存的快照(#75):注册中心按 ip+port+service+group(+cluster)匹配实例,若注销时按当下环境重新推导—— 注册与注销之间 GetPodIP 结果变化(网卡枚举顺序变化/POD_IP 变更)、或 注册时传了 WithGroup/WithCluster 而注销时漏传——就会匹配不到实例, 注销**静默失效**、实例残留在注册中心继续接流量。

没有缓存(本 client 未注册过,如经 Registrar() 逃生口自行注册的调用方) 时退回旧行为:按当下环境与 opts 现算实例身份——此时调用方必须保证 IP/Group/Cluster 与注册时完全一致。注销成功后缓存清除,再次 Deregister 走现算路径。

func (*ServiceClient) DeregisterAs added in v0.5.0

func (c *ServiceClient) DeregisterAs(ctx context.Context, serviceName string, port int, opts ...registry.RegisterOptionFunc) error

DeregisterAs 从注册中心注销指定服务名下的当前服务实例。

与 RegisterAs 配套:实例身份优先取 RegisterAs 成功时缓存的快照(#75), IP/Group/Cluster 不再依赖注销时的环境与 opts;无缓存时按当下环境现算, 调用方须自行保证与注册时一致。

未配置 registrar 时返回 nil(与 Deregister 一致:注销是幂等收尾, 没有 registrar 说明根本没注册过);服务名为空时返回 ErrServiceNameRequired (参数校验先于环境检查)。

func (*ServiceClient) Discoverer added in v0.5.0

func (c *ServiceClient) Discoverer() registry.Discoverer

Discoverer 返回底层注入的发现器;未注入时返回 nil。

逃生口:与 Registrar 配套,让调用方直接驱动发现路径 (如按需携带分组/集群参数拉取实例),连接与生命周期仍归门面。

func (*ServiceClient) GetAllInstances

func (c *ServiceClient) GetAllInstances(ctx context.Context, serviceName string) ([]registry.Instance, error)

GetAllInstances 获取指定服务的全部实例列表(包括不健康的实例)。

与 GetInstances 同一套容错/静态语义(#129——此前两个入口整体分叉:短路 服务照样打注册中心、失败无兜底、空结果不兜底、降级分支把兜底服务当短路 返回,同一配置两个入口给出不同实例面),差别只有两点:

  • 取「全部实例」走 DiscoverAll(含不健康实例);
  • 结果**不写入**实例缓存(实例缓存只存健康视图,供 GetInstances 路由)。

优先序(与 GetInstances 逐级对齐):

  1. 短路语义的静态配置(同 GetInstances 第 1 级)
  2. Mock 模式(同 GetInstances 第 2 级)
  3. 无 Discoverer:新鲜缓存 → 兜底静态 → 报错(同 GetInstances 第 3/4 级)
  4. DiscoverAll(singleflight 保护,"all:" 前缀与 GetInstances 的 flight 分开;失败降级 stale 缓存 → 兜底静态 → 报错,同第 5/6 级)
  5. 空结果兜底静态(同 GetInstances 第 6 级)

返回值契约与 GetInstances 一致:空列表 + nil error 表示「当前无可用实例, 由调用方决定回落」;返回的也是**已发布只读快照**(见 GetInstances 的 快照契约,#149)——DiscoverAll 的结果在 singleflight 出口做一次拷贝与 provider 内存解耦,并发等待方共享同一只读快照。

func (*ServiceClient) GetDepService

func (c *ServiceClient) GetDepService() map[string]*metadata.ServiceBasic

GetDepService 返回依赖服务配置的快照(并发安全)。 注意是结构体浅拷贝:嵌套的指针/map 字段(如 TimeoutRetryCfg)与内部状态共享, 调用方不得修改;并发安全由 WatchService 对字段的整体替换保证。 建议使用此方法而非直接访问内部 depService 字段。

func (*ServiceClient) GetInstances

func (c *ServiceClient) GetInstances(ctx context.Context, serviceName string) ([]registry.Instance, error)

GetInstances 获取服务实例,支持本地缓存和静态配置。

解析优先级(从高到低):

  1. 静态配置(本地开发、测试)——**仅在短路语义下**(见 WithStaticInstances 与 WithStaticFallback 的区别);兜底语义下静态实例不在此步参与
  2. Mock 模式(静态或缓存)
  3. 新鲜缓存(由 Subscribe 推送或上一次 Discover 填充,在 cacheExpiry 内)
  4. 注册中心 Discover(singleflight 保护,避免缓存击穿)
  5. Discover 失败时降级使用缓存(含已过期条目)
  6. 兜底静态实例(WithStaticFallback / FallbackRegistryFirst)——仅在 注册中心路径拿不到实例时参与

第 6 步让「注册中心优先、静态地址兜底」的生产形态成立:注册中心有健康 实例时以注册中心为准(静态地址在实例换 IP 后不会跟着变),注册中心冷启动 或故障时仍有静态地址兜底。

返回值契约:**空列表 + nil error** 表示「当前无可用实例,由调用方决定 回落」(Mock 模式下未配静态实例的名字即走这条路径)。调用方只判 err 不判 len 会把请求路由到空——httpx 的 NNSResolver 判了 len 并回落 baseURL, 本包的契约以此为准。

快照契约(#149,原「每请求深拷贝」契约收紧)

返回的是内部**已发布只读快照**的引用:本包对实例数据只做「发布时一次 深拷贝 + 整体替换」(RCU),绝不原地改写任何已发布的快照,也绝不外泄 provider/调用方拥有的可变内存。因此:

  • 调用方**不得修改**返回的实例(含 Metadata map)——改动对本进程后续 读者可见(热路径零拷贝的代价);需要私有可能改的副本请自行克隆;
  • 持有旧快照的调用方不受后续推送/发现更新影响(更新整体替换,旧快照 内容恒定);
  • 缓存命中热路径零分配(此前每请求深拷贝实例列表 + 每实例一个 Metadata map,nns-endpoint 每请求调用的场景是可测量的稳态分配)。

func (*ServiceClient) GetLocalColor

func (c *ServiceClient) GetLocalColor() string

GetLocalColor 获取本地服务的灰度标识颜色。 颜色来自本地服务元数据,可通过 SetLocalServiceMeta 设置。

func (*ServiceClient) GetLocalRegion

func (c *ServiceClient) GetLocalRegion() string

GetLocalRegion 获取本地服务所在的区域信息。

func (*ServiceClient) GetLocalService

func (c *ServiceClient) GetLocalService() *metadata.ServiceBasic

GetLocalService 获取本地服务的基本配置信息。

func (*ServiceClient) GetRegistrar deprecated

func (c *ServiceClient) GetRegistrar() registry.Registrar

GetRegistrar 返回内部的 registrar 接口(供 nns/kitex 适配器使用)。

Deprecated: 与 Registrar() 完全等价(#146 双访问器收敛)。新代码请用 Registrar();kitex/hertz 适配层迁移完成前本转发保留,之后随 major 删除。

func (*ServiceClient) GetServiceBasic

func (c *ServiceClient) GetServiceBasic(serviceName string) metadata.ServiceBasic

GetServiceBasic 返回指定服务的内存配置(不发起网络请求)。

优先从已加载的 DepService / LocalService 中读取(由 Init 中的 WatchService 保证热更新), 未加载时返回带默认值的 ServiceBasic。供 endpoint 在每次调用时快速读取超时等配置。

func (*ServiceClient) LoadDepService

func (c *ServiceClient) LoadDepService(ctx context.Context, serviceNames []string) error

LoadDepService 加载依赖服务的配置信息。 采用尽力而为策略:即使某个服务加载失败,也会继续加载其余服务。 所有遇到的错误将通过 errors.Join 聚合后返回。

func (*ServiceClient) LocalServiceInit

func (c *ServiceClient) LocalServiceInit(ctx context.Context, serviceName string) (*metadata.ServiceBasic, error)

LocalServiceInit 初始化本地服务,从 Nacos 配置中心拉取服务配置。

func (*ServiceClient) MockMode

func (c *ServiceClient) MockMode() bool

MockMode 返回是否处于 Mock 模式。供 transport 适配器区分 "mock 静默跳过"与"降级(registrar 不可用)"两种 registrar==nil 场景。

func (*ServiceClient) OffConfigChange added in v0.8.0

func (c *ServiceClient) OffConfigChange(handle *ConfigChangeHandle)

OffConfigChange 按 OnConfigChange 返回的句柄注销对应回调。 幂等:nil 句柄、重复注销或句柄已随 Close 清空均为 no-op。

func (*ServiceClient) OnConfigChange

func (c *ServiceClient) OnConfigChange(fn func(serviceName string)) *ConfigChangeHandle

OnConfigChange 注册配置变更回调,返回注销句柄。 当 WatchService 检测到服务配置变更时,所有已注册的回调会被触发; 回调列表在事件分发时现读,注册顺序不影响事件送达。 典型用途:endpoint factory 注册 balancer 缓存重置。

保存返回的句柄并在组件 Close 时传给 OffConfigChange 注销——长生命周期的 ServiceClient 会经回调闭包持有注册方,注册方废弃后不注销则无法回收, 配置事件也会继续打在死组件上(oekit/nns-endpoint#135)。

func (*ServiceClient) Register

func (c *ServiceClient) Register(ctx context.Context, port int, opts ...registry.RegisterOptionFunc) error

Register 向注册中心注册当前服务实例。

服务名取 LocalServiceInit 记录的自身服务名(须先 Init),使用 GetPodIP 探测本机 IP。opts 控制权重、元数据等注册选项。

注册成功后实例身份(IP/Group/Cluster 等)会被缓存(#75):配套的 Deregister 优先用该快照注销,注册与注销之间 GetPodIP 结果变化、或注销时 漏传 WithGroup/WithCluster,都不会再让注销静默失效。

未配置 registrar(mock/未启用注册发现)时是幂等 no-op success(#66), 不返回错误——「本来就没注册」不是故障;no-op 判定先于服务名检查 (#142 收敛前后的行为保持:无 registrar 时即使未 Init 也返回 nil)。

func (*ServiceClient) RegisterAs added in v0.5.0

func (c *ServiceClient) RegisterAs(ctx context.Context, serviceName string, port int, opts ...registry.RegisterOptionFunc) error

RegisterAs 向注册中心注册当前服务实例到**指定服务名**下。

与 Register 的区别只有一处:服务名由调用方显式给出,而不是取 LocalServiceInit 记录的自身服务名。因此 RegisterAs **不要求先 Init**。

一个服务对外暴露多个端点(HTTP + RPC 双协议、分别注册在短名与完整 RPC 服务名下)时,用同一个 SDK 连接把每个名字各注册一次即可——不必 为每个名字各开一个门面实例(那会翻倍 Nacos gRPC 长连接与后台 goroutine)。

端口各自传入(同一进程的两个端点端口不同)。IP 与 Register 一致,取 GetPodIP 探测的本机 IP。opts 控制权重、元数据等注册选项。

配套的注销入口是 DeregisterAs:注册了几个名字就要注销几个名字, 否则注册中心里会留下无人回收的实例。

注册成功后实例身份会被缓存(#75),DeregisterAs 优先用快照注销。

未配置 registrar(mock/未启用注册发现)时是幂等 no-op success(#66), 不返回错误——与 Register 一致,注销对称性不再依赖调用方纪律。 ErrRegistrarUnavailable 自 #66 起**不再被任何入口返回**(仅兼容保留符号, 见其声明),任何 errors.Is(err, ErrRegistrarUnavailable) 分支都不会命中。 服务名为空时返回 ErrServiceNameRequired(参数校验先于环境检查——空服务名 是调用方的错,报「registrar 不可用」会把它掩盖掉)。

func (*ServiceClient) Registrar added in v0.5.0

func (c *ServiceClient) Registrar() registry.Registrar

Registrar 返回底层注入的注册器;未注入时返回 nil。

逃生口:把「注册什么」交还给调用方(如按调用注入不同的实例字段), 而 SDK 连接与生命周期仍由门面持有与释放。与 Discoverer 配套。

func (*ServiceClient) RunWithLifecycle

func (c *ServiceClient) RunWithLifecycle(app lifecycle.App, name string, port int, opts ...registry.RegisterOptionFunc) error

RunWithLifecycle 向注册中心注册当前服务实例,并通过 lifecycle.App 注册 Deregister 作为优雅关闭时的 closer,业务无需手写 Register + Deregister 对称调用。

调用顺序契约(#76):必须在 server 资源注册**之后**调用

lifecycle.App 的 closer 按注册**逆序**执行。本方法注册的 deregister closer 要在关停时**先于** server.Shutdown 执行(先摘流量再停监听,对齐 bootstrap/nacos 组件与 go-kratos Stop 语义),因此 deregister closer 必须 **晚于** server 的 closer 注册——即先启动 server(hertz/kitex RunServer 内部经 app.AddResource 注册 server.Shutdown),再调本方法:

b, _ := bootstrap.New(bootstrap.WithServiceName("svc")) // + nacos/obs WithXxx 按需注入
b.Run(func(app *bootstrap.App) error {
    nnsc := nns.New(nacosBootstrap, opts...)  // 门面负责 provider 默认构造
    h := server.New(server.WithHostPorts(":8080"))
    hertz.RunServer(app, "hertz", h,
        hertz.WithOnReady(func(ctx context.Context) { app.Ready() }))
    // ⚠️ 必须在 RunServer 之后:server closer 先注册 ⇒ 关停逆序执行时
    // nns-deregister 先于 server.Shutdown(先摘流量,再停监听)。
    if err := nnsc.RunWithLifecycle(app, "my-svc", 8080); err != nil {
        return err
    }
    <-app.Context().Done() // 阻塞直到优雅关闭
    return nil
})

反例(旧示例的写法,勿用):先 RunWithLifecycle 再启动 server——关停时 server 先停监听、实例才从注册中心摘除,窗口内 LB 仍把流量路由到已死的 实例。需要「注册严格等到 server 就绪」的语义时,用 bootstrap/nacos 的 WithNNS/WithRequiredNNS(注册延迟到 app.Ready() 之后)。

⚠️ 行为:

  • Register 失败:返回 error,business 决定是否继续(通常 return err 触发整体退出)
  • Register 成功 + lifecycle 关闭:Deregister 在 bootstrap 关闭序列里被调, 走 lifecycle.App.AddResource 的逆序释放约定
  • opts 同时传给 Register 和 Deregister,要求 opts 必须是幂等的(典型场景 只传 weight / metadata / group,业务不要传 random token 之类)

官方依据:ekit lifecycle 契约(lifecycle.App.AddResource)+ Kitex 官方 graceful_shutdown 章节"注册中心注销"步骤

func (*ServiceClient) ServiceConfig added in v0.5.10

func (c *ServiceClient) ServiceConfig(ctx context.Context, serviceName string) (metadata.ServiceBasic, error)

ServiceConfig 拉取指定服务的配置并返回**真实错误**(#77)。

与 ServiceWithName 的差别只在错误面:

  • ServiceWithName 把配置拉取失败/JSON 解析失败静默降级为默认超时值 (软依赖消费方要「有默认值就能跑」);
  • 本方法把错误原样上抛——需要区分「拉到了配置」与「拿到的是兜底默认值」 的调用方(如强依赖配置的启动校验)用它取到真实结果。

错误语义:

  • GetConfig 失败(配置中心不可达等):返回包装后的原始错误;
  • 配置内容 JSON 损坏:返回解析错误(配置写坏应显式暴露,而非静默 降级默认值);
  • 未注入 ConfigStore(mock 之外):返回 ErrConfigStoreUnavailable—— 此前该场景在 GetService 门面上表现为「恒成功 + 默认超时值」;
  • 配置未发布(content 为空)不算错误:返回默认值 + nil,与 ServiceWithName 一致;
  • Mock 模式:取 localServiceConfig,未配置则默认值,不报错。

func (*ServiceClient) ServiceWithName

func (c *ServiceClient) ServiceWithName(ctx context.Context, serviceName string) metadata.ServiceBasic

ServiceWithName 根据服务全名获取服务基本配置。

软依赖语义:配置拉取失败/JSON 解析失败时静默降级——日志 Warn 后返回 默认超时值(硬失败面见 ServiceConfig)。主干与 ServiceConfig 共享 fetchServiceConfig(#144)。

func (*ServiceClient) SetLocalServiceMeta

func (c *ServiceClient) SetLocalServiceMeta(meta map[string]string)

SetLocalServiceMeta 设置本地服务元数据(如 color/region 灰度标识)。 并发安全;传入 nil 等效于清空。典型来源是启动时的环境变量或平台注入。

func (*ServiceClient) SetStaticFallback added in v0.6.0

func (c *ServiceClient) SetStaticFallback(serviceName string, instances []registry.Instance)

SetStaticFallback 设置**兜底**静态实例(覆盖,与 WithStaticFallback 一致 的语义)。

与 SetStaticInstances 的区别只在参与时机:本入口把该服务标记为兜底语义, **不改变发现路径**(#128)。权重口径与 AddStaticFallback 一致。

func (*ServiceClient) SetStaticInstances

func (c *ServiceClient) SetStaticInstances(serviceName string, instances []registry.Instance)

SetStaticInstances 设置静态服务实例(覆盖,**短路**语义,与 WithStaticInstances 一致)。

⚠️ 同 AddStaticInstance:会把该服务切到静态短路(切路径时 Warn); 热加备用地址请用 SetStaticFallback。已有语义标记跟随(fallbackOnly 不被改写)。

权重与注册侧同口径:Weight<=0 回填默认权重 10(见 normalizeStaticInstances)。

func (*ServiceClient) SubscribeService

func (c *ServiceClient) SubscribeService(ctx context.Context, serviceName string, callback func([]registry.Instance)) error

SubscribeService 订阅指定服务的实例变更,当实例列表变化时回调 callback。

SDK 监听按服务去重:同一服务多次订阅只向 provider 注册一次监听, 推送时扇出到全部本地回调(否则 N 次订阅会导致每次推送触发 N² 次回调)。 去重路径(他人已注册监听)下,新回调会立即收到一次当前静态/缓存实例的 初始回调——SDK 推送是事件驱动的,若 provider 首推已过,否则新订阅方会 "看似订阅成功却迟迟无回调"。Close 后调用返回 ErrClientClosed。

回调收到的 []registry.Instance 为**只读快照**(#149):推送路径是与 provider 内存解耦的私有副本,初始回调是内部已发布快照的引用;两者均 不得修改(快照契约见 GetInstances godoc)。

func (*ServiceClient) UnsubscribeService

func (c *ServiceClient) UnsubscribeService(ctx context.Context, serviceName string) error

UnsubscribeService 取消订阅指定服务的实例变更。 本地回调列表同步清除,避免再次 Subscribe 后旧回调重复触发。 注意:取消针对整个服务生效(所有调用方的回调一并清除), SDK 监听同时注销,下次 Subscribe 会重新注册。

并发纪律(#147):「清本地状态 + 标记退订中」与「provider 退订」之间 不是原子的。退订期间(unsubscribing 标记在位)并发 SubscribeService 会 像 etc 等待在途注册一样等待退订落地后再注册新监听——否则本次 provider 退订会把窗口里建立的新监听一并拆除,而本地已视为已订阅 ⇒ 永不重注册, 实例变更推送全部丢失。并发多次 Unsubscribe 收敛:后来者等待首次退订 结束后按「未订阅」状态重入(对 provider 幂等)。

func (*ServiceClient) UnwatchService added in v0.7.0

func (c *ServiceClient) UnwatchService(ctx context.Context, serviceName string) error

UnwatchService 取消指定服务的配置监听(WatchService 的对称退订入口, #148)。

此前配置监听只能随 Close 全量终结:动态增删依赖服务的场景(网关按配置 热加载 dep 列表)里,下线服务的监听与 goroutine 只能积累到进程 Close。 本入口摘除去重标记并 StopListenConfig(ConfigStore 按 dataId 取消监听, Close 路径同款机制),单个服务的配置监听可独立回收。

未监听过的服务是幂等 no-op(返回 nil);Mock 模式或未注入 ConfigStore 时同样 no-op(与 WatchService 的 no-op 对称)。取消后可重新 WatchService。 监听注册是异步的:WatchService 刚返回时后台注册可能尚未完成,此刻调用 本方法对「已在途的注册」由 StopListenConfig 的 dataId 粒度取消兜底。

func (*ServiceClient) WatchService

func (c *ServiceClient) WatchService(ctx context.Context, serviceName string)

WatchService 监听指定服务的配置变更。 内部做去重:同一 serviceName 只注册一次监听。

Jump to

Keyboard shortcuts

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