client

package
v2.0.1 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CONTENT_TYPE_FORM    = "x-form"
	CONTENT_TYPE_JSON    = "json"
	CONTENT_TYPE_RESTFUL = "restful"
	CONTENT_TYPE_FILE    = "file"
)

Variables

View Source
var (
	// ErrCircuitOpen 熔断器处于打开状态,请求被快速失败(未真正发起调用)。
	ErrCircuitOpen = errors.New("client: 熔断器已打开,请求被快速失败")
	// ErrCallTimeout 调用超过 ResilienceOptions.Timeout 仍未返回。
	ErrCallTimeout = errors.New("client: 微服务调用超时")
)

调用级韧性策略的错误哨兵,便于调用方用 errors.Is 判断。

View Source
var ErrAllInstancesCircuitOpen = errors.New("client: all instances circuit-open")

ErrAllInstancesCircuitOpen v2 负载均衡专用错误:当服务的全部实例都被熔断时返此错误, 调用方可以快速失败(避免对已挂掉的下游继续施压)。

Functions

func Call

func Call(service, uri string, op *Options) (string, error)

Call 是 v1 时代的微服务调用入口,等价于 CallCtx(context.Background(), service, uri, op)。 保留以兼容存量项目;新代码建议直接使用 CallCtx 以便传入 context(例如超时/取消)。

func CallCtx

func CallCtx(ctx context.Context, service, uri string, op *Options) (string, error)

CallCtx 是 v2 新增的"支持 context"版本微服务调用入口。

背景:v1 的 Call 不支持 context,导致:

  • 无法把 ctx 透传到 grequests 底层(grequests 的 DoRegularRequest 不接受 ctx)
  • 业务侧无法用 ctx 实现超时或链路取消

v2 决策(已与用户确认):**保持 goroutine+timer 兑底**, 即调用方在 CallCtx 内部通过 ctx 控制的超时计时器来"及时返回",但底层 HTTP 请求 不会被真正取消,仍会占用连接到对端响应或连接超时。要做到真正取消需要升级 `levigross/grequests` 或换 net/http 自封装,那是 v2.1+ 的工作。

ctx 在本函数的作用:

  • 通过 grequests 兼容的 RequestOptions 携带(未来 SDK 支持时直接生效)
  • 用于超时/取消的"上层兜底"(业务可在外层用 select 控制)
  • 链路 trace header 由 trace.GetHeaders() 透传,与 ctx 无关

func CallCtxT

func CallCtxT[T any](ctx context.Context, service, uri string, op *Options) models.Result[T]

CallCtxT 是 CallT 的 context 版本,语义对齐 CallCtx。

func CallResilient

func CallResilient(service, uri string, op *Options, ro *ResilienceOptions) (string, error)

CallResilient 在 client.Call 之上叠加超时、指数退避(带 jitter)重试与熔断。

幂等性保护(非常重要):

  • 幂等读(GET / HEAD / OPTIONS / TRACE)默认可重试;
  • 非幂等写(POST / PUT / DELETE / PATCH)默认不重试,避免重复下单、重复扣款等副作用;
  • 唯一例外:调用方显式提供 RetryOnStatus,且从错误中解析出的状态码被该回调判定为可重试;
  • Options.Method 为空时,按 client.Call 的既有默认值视为 POST(非幂等,默认不重试)。

默认安全:ro 为 nil 或其所有字段为零值时,等价于直接调用一次 client.Call (不重试、不超时、不熔断),既有调用方不受任何影响。

参数:

  • service: 微服务名。
  • uri: 接口路径。
  • op: 调用参数,与原 client.Call 一致;函数不会修改调用方传入的 op。
  • ro: 韧性策略,可为 nil。

返回值:

  • string: 成功时返回响应体,与原 client.Call 一致。
  • error: 失败时返回最后一次的错误;熔断打开时返回包装了 ErrCircuitOpen 的错误。

CallResilient 是 Call 的"带韧性策略"版本,等价于 CallResilientCtx(context.Background(), service, uri, op, ro)。 保留以兼容 v1 时代使用 CallResilient 的项目。

func CallResilientCtx

func CallResilientCtx(ctx context.Context, service, uri string, op *Options, ro *ResilienceOptions) (string, error)

CallResilientCtx 是 CallResilient 的 context 版本(v2 新增)。

与 CallResilient 的差异:把 context 透传到 callWithTimeout 的 goroutine 调用链, 调用方可在 ctx 中带超时或取消信号。需要 ctx 真正取消底层 HTTP 时, 当前实现是"goroutine+timer 兑底"(见 v2-design §6.2),不依赖 grequests 升级。

func CallT

func CallT[T any](service, uri string, op *Options) models.Result[T]

func ResetBreakers

func ResetBreakers()

ResetBreakers 清空全局熔断器注册表,主要用于测试场景。

Types

type CircuitBreaker

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

CircuitBreaker 一个轻量三态熔断器。

采用纯标准库实现(sync/atomic 未使用,统一用互斥锁保护状态), 不引入 gobreaker / hystrix 等第三方依赖,避免给框架增加依赖负担。

计数模型:固定窗口计数(窗口长度 interval),窗口到期或发生状态跳转时清零重新计数。 该模型足够覆盖微服务调用保护场景,且实现简单、无额外内存开销。

func GetBreaker

func GetBreaker(name string) *CircuitBreaker

GetBreaker 按名称获取(或首次创建)一个全局共享的熔断器。 未显式指定参数时使用默认阈值:60 秒窗口内失败 5 次即熔断,冷却 30 秒后半开探测。 需要自定义参数时请使用 NewCircuitBreaker 并把结果赋给 ResilienceOptions.Breaker。

func NewCircuitBreaker

func NewCircuitBreaker(name string, maxFailures int, interval, timeout time.Duration) *CircuitBreaker

NewCircuitBreaker 创建一个熔断器。 参数:

  • name: 熔断器名称,用于日志与 String()。
  • maxFailures: 计数窗口内失败次数阈值,<=0 时使用 defaultMaxFailures。
  • interval: 失败计数窗口长度,<=0 时使用 defaultBreakerInterval。
  • timeout: 熔断打开后的冷却时长,<=0 时使用 defaultBreakerTimeout。

func (*CircuitBreaker) Allow

func (cb *CircuitBreaker) Allow() bool

Allow 判断当前请求是否允许放行。 熔断打开且未到冷却时间时返回 false(快速失败);冷却时间到达时会自动切换到半开并放行探测请求。 一旦 Allow 返回 true,调用方必须在请求结束后调用 Success() 或 Failure() 归还半开配额。

func (*CircuitBreaker) Counts

func (cb *CircuitBreaker) Counts() (failures int, successes int)

Counts 返回当前计数窗口内的失败次数与成功次数。

func (*CircuitBreaker) Failure

func (cb *CircuitBreaker) Failure()

Failure 上报一次失败结果。

func (*CircuitBreaker) Name

func (cb *CircuitBreaker) Name() string

Name 返回熔断器名称。

func (*CircuitBreaker) Reset

func (cb *CircuitBreaker) Reset()

Reset 强制把熔断器恢复到关闭状态并清零计数。

func (*CircuitBreaker) State

func (cb *CircuitBreaker) State() State

State 返回熔断器当前状态。

func (*CircuitBreaker) String

func (cb *CircuitBreaker) String() string

String 返回熔断器的可读描述,用于错误信息与日志。

func (*CircuitBreaker) Success

func (cb *CircuitBreaker) Success()

Success 上报一次成功结果。

type Options

type Options struct {
	Method   string                 `json:"method"`   //接口方法 GET|POST|PUT|DELETE
	Protocol string                 `json:"protocol"` //协议 x-form|json|restful
	Group    string                 `json:"group"`    //应用分组,用于nacos中分组,不传为当前nacos分组及默认分组
	Header   any                    `json:"header"`   //额外的头部参数
	Query    any                    `json:"query"`    //URL Query参数
	Data     any                    `json:"data"`     //x-form Postform参数
	Json     any                    `json:"json"`     //json或restful模式的body参数
	Path     map[string]string      `json:"path"`     //restful模式的路径参数
	Files    []grequests.FileUpload //文件上传数据
	Retry    bool                   `json:"retry"` //是否重试

	// v2 新增:负载均衡相关字段(可选,零侵入)。
	// LoadBalancer 为空时走 loadbalancer.Default()(RoundRobin)。
	// 命名常量参见 pkg/loadbalancer:roundrobin / random / leastconn / consistenthash。
	LoadBalancer string `json:"loadbalancer,omitempty"`
}

type ResilienceOptions

type ResilienceOptions struct {
	// Timeout 单次调用的超时时间。<=0 表示不启用超时(与现有行为一致)。
	Timeout time.Duration
	// MaxRetries 除首次调用外最多重试的次数。<=0 表示不重试(与现有行为一致)。
	MaxRetries int
	// BaseDelay 指数退避的初始延迟,<=0 时使用 defaultBaseDelay(100ms)。
	BaseDelay time.Duration
	// MaxDelay 指数退避的延迟上限,<=0 时使用 defaultMaxDelay(2s)。
	MaxDelay time.Duration
	// RetryOnStatus 判定哪些 HTTP 状态码可重试。
	//
	// 【重要限制】现有 client.Call 的返回值只有响应体字符串与 error:
	// 非 2xx 响应(如 500/503)在 grequests 层面并不算 error,会以正常响应体返回,
	// 因此通过 CallResilient 调用时通常拿不到状态码,本回调也就不会被触发。
	// 只有当错误文本中出现形如 "status code 503" / "HTTP 500" / "code=502" 的
	// 状态码信息时(自定义错误、网关错误、未来 Call 返回带状态码的错误)才会生效。
	// 解析失败时回退到下面的幂等性默认策略。
	// 若后续允许为 Options 增加可选的状态码输出字段,本回调即可完整生效。
	RetryOnStatus func(code int) bool
	// Breaker 熔断器,nil 表示不启用熔断。可用 client.GetBreaker(service) 获取全局共享实例。
	Breaker *CircuitBreaker
}

ResilienceOptions 描述在 client.Call 之外叠加的韧性策略。 所有字段都是可选的;零值 / nil 表示“不使用该能力”,行为与直接调用 client.Call 完全一致。

type State

type State int

State 表示熔断器当前所处的状态。

const (
	StateClosed State = iota
	StateHalfOpen
	StateOpen
)

熔断器三态:

Closed   —— 关闭(正常):请求正常放行,失败计数达到阈值后跳转 Open
Open     —— 打开(熔断):请求被快速失败,冷却时间到达后跳转 HalfOpen
HalfOpen —— 半开(探测):放行少量请求做探测,成功则回到 Closed,失败则立刻回到 Open

func (State) String

func (s State) String() string

String 返回状态的中文名,便于日志阅读。

Jump to

Keyboard shortcuts

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