invocation

package
v1.4.2 Latest Latest
Warning

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

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 12 Imported by: 2

README

Invocation

invocation 包定义 Firefly 当前唯一推荐的出站服务调用模型。

除本文件外,其余说明文档已统一迁移到 docs/ 目录。

它只负责四件事:

  • DNS 表达远程业务服务
  • 把 DNS 组装成稳定的 gRPC target
  • 复用 grpc.ClientConn
  • 统一构造出站 metadata 与 timeout

它不负责运行时治理能力:

  • 实例发现
  • 节点选择
  • Consul / K8s 后端适配
  • endpoint 轮询

文档索引

  • docs/ARCHITECTURE.md:看清组件职责、边界和完整调用时序
  • docs/USAGE.md:看实际装配方式、repo 接入模式和示例
  • docs/CONTEXT-USAGE.md:查看旧上下文模型废弃说明
  • docs/TESTING.md:查看测试范围、覆盖率和测试结论
  • docs/PERFORMANCE.md:查看基准测试、性能对比和基线
  • docs/TEST_REPORT.md:兼容历史链接入口

一句话主线

当前推荐主线只有一条:

  1. 启动装配层创建 DNSManager
  2. 启动装配层创建 ConnectionManager
  3. 启动装配层创建 UnaryInvoker
  4. 启动装配层创建 RemoteServiceManaged
  5. repo 在 New*Repo(...) 中通过 services.Caller("service") 绑定 RemoteServiceCaller
  6. repo 方法只保留 full method + req + resp

如果 repo 只依赖一个远程业务服务,也可以直接装配 RemoteServiceCaller

核心对象

DNS

远程业务服务的标准 DNS 描述。

推荐直接使用字面量,不再额外包一层 builder 或 option helper。

DNSManager

负责默认值补齐、最小校验和最终 Target 构造。

ConnectionManager

负责按最终 gRPC target 复用连接。

UnaryInvoker

负责底层真实调用:

  • 复用当前链路 metadata
  • 注入 ServiceAppId / ServiceInstanceId
  • 使用初始化时注入的统一 timeout
  • 发起真实 gRPC unary 调用
RemoteServiceCaller

repo 级远程业务服务调用入口。

适合“当前 repo 已经明确绑定一个远程业务服务”的场景。

RemoteServiceManaged

多业务服务注册表。

适合“当前服务依赖多个远程业务服务”的场景,用来:

  • 统一登记多组 DNS
  • 统一复用一个 UnaryInvoker
  • 按服务名派生 RemoteServiceCaller

推荐接入方式

推荐分成两层装配:

  • 启动装配层:维护“本服务依赖哪些远程业务服务”
  • repo 层:维护“当前 repo 绑定哪个远程业务服务 caller”

建议目录分工:

  • provider / bootstrap / internal/dep:创建 RemoteServiceManaged
  • internal/data/rs_*.go:在 New*Repo(...) 中绑定 RemoteServiceCaller
  • repo 方法:只保留 full method + req + resp

完整示例见 docs/USAGE.md

关键约束

  • 一个远程业务服务只维护一份 DNS
  • 同一业务服务下多个 proto 子服务共用同一份 DNS 和连接
  • 具体 RPC 由 gRPC full method 决定
  • UnaryInvoker 不再作为 repo 层首选装配入口
  • 不再暴露 metadata / timeout 的单次调用覆盖能力

快速示例

package example

import (
	"time"

	"github.com/fireflycore/go-micro/invocation"
)

func BuildRemoteServices(manager *invocation.ConnectionManager) *invocation.RemoteServiceManaged {
	invoker := invocation.NewUnaryInvoker(manager, "config", "config-1", 3*time.Second)

	return invocation.NewRemoteServiceManaged(
		invoker,
		invocation.DNS{Service: "auth"},
		invocation.DNS{Service: "iam"},
	)
}

从哪里继续看

  • 想看职责边界和完整时序:docs/ARCHITECTURE.md
  • 想看 repo 怎么接入:docs/USAGE.md
  • 想确认旧上下文为什么废弃:docs/CONTEXT-USAGE.md
  • 想看测试现状:docs/TESTING.md
  • 想看性能基线:docs/PERFORMANCE.md

Documentation

Overview

Package invocation 定义面向 service-to-service 调用模型的核心错误。

Index

Constants

View Source
const (
	// DefaultResolverScheme 是 gRPC 默认推荐使用的 DNS resolver scheme。
	DefaultResolverScheme = "dns"
	// DefaultNamespace 是业务服务默认使用的命名空间。
	DefaultNamespace = "default"
	// DefaultServiceType 是 Kubernetes Service FQDN 中的固定服务类型片段。
	DefaultServiceType = "svc"
	// DefaultClusterDomain 是 Kubernetes 集群默认的 Cluster Domain。
	DefaultClusterDomain = "cluster.local"
	// DefaultServicePort 是业务服务默认使用的 gRPC 端口。
	DefaultServicePort = 9090
)
View Source
const (
	// DefaultInvokeTimeout 是统一的默认远程调用超时时间。
	DefaultInvokeTimeout = 5 * time.Second
)

Variables

View Source
var (
	// ErrServiceNameEmpty 表示服务名为空,无法构造逻辑服务身份。
	ErrServiceNameEmpty = errors.New("service name is empty")
	// ErrNamespaceEmpty 表示命名空间为空。
	ErrNamespaceEmpty = errors.New("namespace is empty")
	// ErrTargetHostEmpty 表示目标主机为空,无法生成最终拨号地址。
	ErrTargetHostEmpty = errors.New("target host is empty")
	// ErrTargetPortInvalid 表示端口既未显式提供,也无法从默认值中补齐。
	ErrTargetPortInvalid = errors.New("target port is invalid")
	// ErrDNSManagerIsNil 表示 DNS 管理器为空。
	ErrDNSManagerIsNil = errors.New("dns manager is nil")
	// ErrDialFnIsNil 表示底层拨号函数为空。
	ErrDialFnIsNil = errors.New("dial function is nil")
	// ErrConnectionManagerClosed 表示连接管理器已经关闭,不能再创建新连接。
	ErrConnectionManagerClosed = errors.New("connection manager is closed")
	// ErrInvokerDialerIsNil 表示调用器缺少拨号器依赖。
	ErrInvokerDialerIsNil = errors.New("invoker dialer is nil")
	// ErrInvokeMethodEmpty 表示调用方法名为空。
	ErrInvokeMethodEmpty = errors.New("invoke method is empty")
	// ErrRemoteServiceNotFound 表示未找到指定远程业务服务。
	ErrRemoteServiceNotFound = errors.New("remote service not found")
)

Functions

func DefaultDialFunc

func DefaultDialFunc(_ context.Context, target Target, options []grpc.DialOption) (*grpc.ClientConn, error)

DefaultDialFunc 是默认的 grpc.ClientConn 创建逻辑。

当前实现采用 grpc.NewClient,并默认启用: - insecure credentials:便于在内部受控网络中快速起步; - otelgrpc client handler:保证调用链路自动接入 OTel。

后续若需要在具体实现中启用 mTLS、自定义 resolver 或更多 dial option, 可以通过 ConnectionManagerOptions 覆盖该行为。

func NewOutgoingCallContext added in v1.4.0

func NewOutgoingCallContext(parent context.Context, md metadata.MD, timeout time.Duration) (context.Context, context.CancelFunc)

NewOutgoingCallContext 基于父 context、metadata 和 timeout 构造新的 gRPC 出站 context。

这里保留父 context 的取消信号与已有 deadline, 避免像旧实现那样切断上游取消传播。

Types

type ConnectionManager

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

ConnectionManager 负责缓存基于 DNS 创建出的 grpc.ClientConn。

它把“业务服务 DNS -> 目标解析 -> 连接缓存”统一收敛在一处, 让业务层无需关心: - target 拼装; - resolver scheme; - 拨号选项; - 多次调用的连接复用。

func NewConnectionManager

func NewConnectionManager(options ConnectionManagerOptions) (*ConnectionManager, error)

NewConnectionManager 创建连接管理器。

func (*ConnectionManager) Close

func (m *ConnectionManager) Close() error

Close 关闭连接管理器及其持有的全部 grpc.ClientConn。

Close 会尽最大努力关闭所有连接; 若中途出现错误,当前实现返回第一条错误并继续关闭剩余连接。

func (*ConnectionManager) Dial

func (m *ConnectionManager) Dial(ctx context.Context, dns *DNS) (*grpc.ClientConn, error)

Dial 根据 DNS 获取或创建对应的 grpc.ClientConn。

连接缓存键采用最终 gRPC target,而不是 DNS 原始字段, 这样可以保证: - 逻辑上等价的服务身份只会生成一条连接; - 端口覆盖、cluster domain、resolver scheme 的变化都能体现在缓存键上。

type ConnectionManagerOptions

type ConnectionManagerOptions struct {
	// DNSManager 用于把业务服务 DNS 描述解析为最终 Target。
	DNSManager *DNSManager
	// DialFunc 用于创建新的 grpc.ClientConn。
	// 若为空,则使用默认拨号实现。
	DialFunc DialFunc
	// DialOptions 表示创建 grpc.ClientConn 时使用的附加选项。
	DialOptions []grpc.DialOption
}

ConnectionManagerOptions 定义连接管理器的配置。

type DNS added in v1.4.2

type DNS struct {
	// Service 表示业务服务名,例如 auth。
	Service string `json:"service"`
	// Namespace 表示命名空间,例如 default。
	Namespace string `json:"namespace"`
	// ServiceType 表示服务类型片段,默认值通常为 svc。
	ServiceType string `json:"service_type"`
	// ClusterDomain 表示集群域,默认值通常为 cluster.local。
	ClusterDomain string `json:"cluster_domain"`
	// Port 表示业务服务监听端口,默认值通常为 9090。
	Port uint16 `json:"port"`
}

DNS 表示一个远程业务服务的标准 DNS 配置。

这里表达的是“这个业务服务在网络上的稳定入口”, 而不是“这个服务当前有哪些实例”。

func (*DNS) Build added in v1.4.2

func (d *DNS) Build(service string) string

Build 返回服务的 DNS 名称,例如 demo.default.svc.cluster.local。

func (*DNS) BuildAddress added in v1.4.2

func (d *DNS) BuildAddress(service string) string

BuildAddress 返回服务的 DNS 地址,例如 demo.default.svc.cluster.local:9090。

func (*DNS) Normalize added in v1.4.2

func (d *DNS) Normalize()

Normalize 补齐 DNS 的默认值。

type DNSConfig added in v1.3.7

type DNSConfig struct {
	// DefaultNamespace 表示默认命名空间。
	DefaultNamespace string
	// DefaultServiceType 表示默认服务类型片段。
	DefaultServiceType string
	// DefaultClusterDomain 表示默认集群域名。
	DefaultClusterDomain string
	// DefaultPort 表示默认端口。
	DefaultPort uint16
	// ResolverScheme 表示默认 gRPC resolver scheme。
	ResolverScheme string
}

DNSConfig 定义标准 DNS 管理器的默认行为。

type DNSManager added in v1.3.7

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

DNSManager 负责把结构化的 DNS 转成最终 Target。

它只做一件事:组装标准 DNS。 它不做实例发现、不做节点选择,也不做后端适配。

func NewDNSManager added in v1.3.7

func NewDNSManager(config *DNSConfig) *DNSManager

NewDNSManager 创建一个标准 DNS 管理器。

func (*DNSManager) Build added in v1.3.7

func (m *DNSManager) Build(dns *DNS) (*Target, error)

Build 根据 DNS 构造最终 Target。

func (*DNSManager) Config added in v1.3.7

func (m *DNSManager) Config() *DNSConfig

Config 返回当前管理器的规范化配置副本。

func (*DNSManager) Normalize added in v1.3.7

func (m *DNSManager) Normalize(dns *DNS) *DNS

Normalize 用默认配置补齐业务服务 DNS。

type DialFunc

type DialFunc func(ctx context.Context, target Target, options []grpc.DialOption) (*grpc.ClientConn, error)

DialFunc 表示底层拨号函数。

把拨号过程抽象成函数有两个目的: 1. 让 ConnectionManager 在不依赖具体后端的情况下复用连接; 2. 让单元测试可以替换真实拨号逻辑,避免触发真实网络连接。

type Dialer

type Dialer interface {
	// Dial 根据业务服务 DNS 返回可复用的 gRPC 连接。
	Dial(ctx context.Context, dns *DNS) (*grpc.ClientConn, error)
	// Close 释放 Dialer 持有的底层资源。
	Close() error
}

Dialer 定义“如何把业务服务 DNS 变成 grpc.ClientConn”。

在新模型中,Dialer 只关心: - 标准 DNS target 组装结果; - 连接复用; - gRPC 连接创建。

type Invoker

type Invoker interface {
	// Invoke 对指定远程业务服务发起一次标准 unary 调用。
	Invoke(ctx context.Context, dns *DNS, method string, req any, resp any, callOptions ...grpc.CallOption) error
}

Invoker 定义统一调用入口。

与业务代码直接操作 grpc.ClientConn 不同, Invoker 允许框架在调用前统一完成: - 业务服务 DNS 目标解析; - metadata 注入; - 底层连接复用。

type RemoteServiceCaller added in v1.3.8

type RemoteServiceCaller struct {
	// Service 表示当前远程业务服务的标准 DNS 身份。
	Service *DNS
	// Invoker 负责统一的连接获取、metadata 注入和实际调用。
	//
	// 当前约束下 RemoteServiceCaller 只是一个薄封装,
	// 真正的调用行为仍全部落在 UnaryInvoker 上。
	Invoker *UnaryInvoker
}

RemoteServiceCaller 表示一个远程业务服务的通用调用入口。

这个对象绑定的是“远程业务服务”而不是“某个 proto 子服务”。 因此一个业务服务下多个 proto 子服务,应共用同一个 RemoteServiceCaller。

例如: - auth 业务服务

  • AuthAppService
  • AuthUserService
  • AuthPermissionService

这些子服务都应共用一份: - DNS - ConnectionManager - UnaryInvoker

func NewRemoteServiceCaller added in v1.3.9

func NewRemoteServiceCaller(invoker *UnaryInvoker, dns *DNS) *RemoteServiceCaller

NewRemoteServiceCaller 创建一个标准的远程业务服务调用器。

这个构造函数的目标是把业务侧最常见的装配模板统一收口: - 指定远程业务服务 DNS; - 指定统一复用的 UnaryInvoker。

func (*RemoteServiceCaller) Invoke added in v1.3.8

func (c *RemoteServiceCaller) Invoke(ctx context.Context, method string, req any, resp any, callOptions ...grpc.CallOption) error

Invoke 对当前绑定的远程业务服务发起一次 unary 调用。

调用方只需要提供: - full method - request - response

其余通用逻辑由 DNS 与 UnaryInvoker 统一处理。

type RemoteServiceManaged added in v1.4.1

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

RemoteServiceManaged 管理多组远程业务服务 DNS,并复用同一个调用主线。

这个对象只解决三件事: - 统一登记多组远程业务服务; - 统一复用同一个 UnaryInvoker; - 按业务服务名派生 caller 或直接发起 full method 调用。

func NewRemoteServiceManaged added in v1.4.1

func NewRemoteServiceManaged(invoker *UnaryInvoker, services ...DNS) *RemoteServiceManaged

NewRemoteServiceManaged 创建一个轻量的多业务服务装配器。

func (*RemoteServiceManaged) Caller added in v1.4.1

func (r *RemoteServiceManaged) Caller(serviceName string) (*RemoteServiceCaller, error)

Caller 为指定业务服务派生一个复用主调用器的 RemoteServiceCaller。

func (*RemoteServiceManaged) DNS added in v1.4.1

func (r *RemoteServiceManaged) DNS(serviceName string) (*DNS, error)

DNS 返回指定业务服务名对应的 DNS 副本。

func (*RemoteServiceManaged) Invoke added in v1.4.1

func (r *RemoteServiceManaged) Invoke(ctx context.Context, serviceName string, method string, req any, resp any, callOptions ...grpc.CallOption) error

Invoke 按业务服务名直接发起一次标准 unary 调用。

type Target

type Target struct {
	// ResolverScheme 表示 gRPC resolver scheme,例如 dns。
	ResolverScheme string `json:"resolver_scheme"`
	// Host 表示服务的标准主机名。
	Host string `json:"host"`
	// Port 表示服务端口。
	Port uint16 `json:"port"`
	// contains filtered or unexported fields
}

Target 表示最终可拨号的 gRPC 服务目标。

它已经不表达实例列表,只表达一个稳定的服务入口。

func (Target) Address

func (t Target) Address() string

Address 返回标准的 host:port 地址。

func (Target) GRPCTarget

func (t Target) GRPCTarget() string

GRPCTarget 返回适合 grpc.NewClient 使用的 target 字符串。

func (Target) Validate

func (t Target) Validate() error

Validate 检查 Target 是否可以用于真实拨号。

type UnaryInvokeFunc

type UnaryInvokeFunc func(ctx context.Context, conn *grpc.ClientConn, method string, req any, resp any, options ...grpc.CallOption) error

UnaryInvokeFunc 表示底层 unary 调用函数。

通过把真实调用抽象成函数, 可以让 UnaryInvoker 在测试中替换掉真实的 grpc.ClientConn.Invoke。

type UnaryInvoker

type UnaryInvoker struct {
	// Dialer 负责连接获取与复用。
	Dialer Dialer
	// ServiceAppId 表示当前发起调用的服务应用标识。
	ServiceAppId string
	// ServiceInstanceId 表示当前发起调用的服务实例标识。
	ServiceInstanceId string
	// Timeout 表示统一的远程调用超时时间;未设置时默认 5s。
	Timeout time.Duration
	// InvokeFunc 是可选依赖;若为空,则默认调用 grpc.ClientConn.Invoke。
	InvokeFunc UnaryInvokeFunc
}

UnaryInvoker 是默认的 Invoker 实现。

它的执行流程非常明确: 1. 基于 DNS 获取连接; 2. 基于当前链路 metadata 构造统一出站上下文,并注入服务自身身份; 3. 使用 grpc.ClientConn.Invoke 发起 unary 调用。

func NewUnaryInvoker added in v1.4.1

func NewUnaryInvoker(dialer Dialer, serviceAppId string, serviceInstanceId string, timeout time.Duration) *UnaryInvoker

NewUnaryInvoker 创建一个带服务自身身份配置的统一调用器。

func (*UnaryInvoker) Invoke

func (u *UnaryInvoker) Invoke(ctx context.Context, dns *DNS, method string, req any, resp any, callOptions ...grpc.CallOption) error

Invoke 执行一次标准 unary 调用。

Jump to

Keyboard shortcuts

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