invocation

package
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: MIT Imports: 13 Imported by: 2

README

Invocation

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

它只解决四件事:

  • 业务侧如何使用 service.DNS 声明一个远程业务服务的标准 DNS
  • 如何把 DNS 组装成稳定的 gRPC target
  • 如何复用 grpc.ClientConn
  • 如何统一传递 metadata

不再负责:

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

核心理念

业务服务之间的调用,本质上就是面向一个稳定的业务服务 DNS。

例如:

auth.default.svc.cluster.local:9090

含义如下:

  • auth:业务服务名
  • default:命名空间
  • svc:Kubernetes Service 类型片段
  • cluster.local:Cluster Domain
  • 9090:业务服务端口

业务代码只需要表达这份 DNS 结构。

后续流量如何命中实例:

  • 裸机环境交给 sidecar-agent
  • 云原生环境交给 K8s

当前模型

service.DNS

service.DNS 表示业务服务的标准 DNS 配置。

它直接描述:

  • service
  • namespace
  • service_type
  • cluster_domain
  • port

当前推荐直接使用 service.DNS 字面量。

除非后续出现稳定且跨仓库复用的构造规则,否则不建议再额外包一层 service.DNS builder 或 option helper。

DNSManager

DNSManager 只负责补齐默认值并构造最终 Target

它不会做:

  • endpoint 拉取
  • 实例选择
  • 后端适配

它会做的最小校验只有两类:

  • 远程业务服务名不能为空
  • 命名空间不能为空
ConnectionManager

ConnectionManager 负责:

  • 基于 service.DNS 构造 Target
  • 按最终 gRPC target 缓存连接
  • 统一挂载 gRPC client dial options
UnaryInvoker

UnaryInvoker 负责:

  • 取连接
  • 注入调用 metadata
  • 注入当前服务自身的 ServiceAppId / ServiceInstanceId
  • 发起真实 gRPC unary 调用

当前代码组织上,DialerInvokerUnaryInvoker 已统一收口在 invoker.go,避免把很薄的契约层单独拆成一个文件。

推荐优先通过 NewUnaryInvoker(...) 装配,显式传入当前服务自身身份。

RemoteServiceCaller

RemoteServiceCaller 是在 UnaryInvoker 之上提供的一层薄封装。

它解决的问题不是“替代 gRPC”,而是把业务 repo 里重复出现的这组样板收口:

  • 绑定一个远程业务服务的 service.DNS
  • 复用同一个 UnaryInvoker
  • 让 repo 方法只保留 full method + req + resp

它绑定的是“远程业务服务”,不是某个 proto 子服务。

当前推荐直接通过 NewRemoteServiceCaller(...) 完成标准装配。

RemoteServiceManaged

RemoteServiceManaged 提供一层轻量的多业务服务装配能力。

它只负责:

  • 统一登记多组远程业务服务 service.DNS
  • 统一复用同一个 UnaryInvoker
  • 按业务服务名返回 RemoteServiceCaller
  • 按业务服务名直接发起 full method 调用
Invoke Contract

当前调用侧不再暴露 metadata / timeout 的单次调用覆盖能力。

统一约束如下:

  • UnaryInvoker 直接复用当前链路 metadata
  • UnaryInvoker 会在出站前注入 ServiceAppId / ServiceInstanceId
  • 远程调用 timeout 在 NewUnaryInvoker(...) 初始化时注入
  • 未显式配置 timeout 时,默认使用 5s

当前文件结构

当前目录按职责拆分为:

  • dns.goDNSConfigDNSManager 和 DNS 规范化逻辑
  • target.goTarget 和最终 gRPC target 表达
  • manager.goConnectionManager 和连接缓存/拨号逻辑
  • invoker.goDialerInvokerUnaryInvoker 与出站上下文构造
  • caller.goRemoteServiceCaller
  • service.goRemoteServiceManaged
  • error.go:统一错误定义
  • TEST_REPORT.md:当前测试覆盖率、基准与性能对比报告

一个业务服务多个 proto 子服务

这是当前模型里的重要约束:

  • 一个远程业务服务只维护一份 service.DNS
  • 同一个业务服务下的多个 proto 子服务,共用同一份 DNS 和连接
  • 具体调用哪个子服务,由 gRPC full method 决定

例如:

  • 远程业务服务:auth
  • proto 子服务:
    • AuthAppService
    • AuthUserService
    • AuthPermissionService

这些调用都应该共用:

auth.default.svc.cluster.local:9090

推荐接入方式

业务服务应在自己的 internal/data/rs_*.go 中,按“远程业务服务”聚合配置。

推荐做法:

  • 在服务启动时集中声明多组远程业务服务 service.DNS
  • 统一创建一份 ConnectionManager / UnaryInvoker / RemoteServiceManaged
  • New*Repo 中按业务服务名获取 caller
  • 通过不同 full method 区分具体 proto 子服务

不推荐做法:

  • 按每个 proto 子服务单独维护一份远程地址配置
  • 在调用侧做实例发现
  • 在调用侧感知 Consul / K8s 细节

为什么不是直接 grpc client

generated gRPC client 本身没有问题,但它更适合解决:

  • 我已经拿到了 grpc.ClientConn
  • 我已经知道要调哪个 stub client
  • 我现在只需要发起 RPC

而 invocation 当前要统一的是另一层语义:

  • 业务服务 DNS 如何表达
  • 连接如何统一复用
  • metadata 如何统一透传
  • OTel 如何统一接入

如果继续让每个 repo 直接面向 generated gRPC client:

  • 上下文构造容易散在不同 repo 中
  • metadata 透传容易出现不一致
  • 调用前的统一能力不好收口

因此当前推荐是:

  • UnaryInvoker 作为底层统一调用器
  • RemoteServiceCaller 作为远程业务服务级别的薄封装
  • 多业务服务装配优先使用 RemoteServiceManaged
  • generated gRPC client 不作为内部统一调用主模型

为什么不再提供默认上下文拼装 helper

根据最新边界约束:

  • ServiceContext 仅供服务内读取,不反向成为出站调用参数来源
  • IncomingContext / OutgoingContext 只是 transport metadata 语义,不在 invocation 中额外落成公共上下文对象
  • 服务调用时若需要沿链路透传上下文,本质上应直接复用 metadata,而不是从服务内上下文对象反向拼装

服务端边界

invocation 只负责出站调用语义。

服务端入站 metadata 解析与主上下文注入由 middleware/grpc 负责,服务内读取入口由 service 包负责:

  • gm.NewServiceContextUnaryInterceptor(...)
  • service.FromContext(...)

启动到调用时序

下面这张图描述当前推荐主线下,从服务启动装配 invocation,到一次下游调用真正发出的完整时序:

sequenceDiagram
    participant Boot as Service Bootstrap
    participant Repo as Repo/Data
    participant RSM as RemoteServiceManaged
    participant RSC as RemoteServiceCaller
    participant UI as UnaryInvoker
    participant CM as ConnectionManager
    participant DM as DNSManager
    participant MG as middleware/grpc
    participant RT as Runtime(K8s/sidecar)
    participant Down as Downstream Service

    Boot->>DM: NewDNSManager(DNSConfig)
    Boot->>CM: NewConnectionManager(DNSManager, DialOptions)
    Boot->>UI: NewUnaryInvoker(manager, serviceAppId, serviceInstanceId, timeout)
    Boot->>RSM: NewRemoteServiceManaged(invoker, service.DNS...)
    Boot->>Repo: 注入 repo 依赖

    Note over MG,Repo: 一次入站请求到达当前服务
    MG->>MG: 解析 incoming metadata
    MG->>MG: Build ServiceContext
    MG->>Repo: 业务方法获得 ctx

    Repo->>RSM: Caller("auth") / Invoke("auth", fullMethod, req, resp)
    RSM->>RSM: 按服务名查找 service.DNS
    RSM->>RSC: NewRemoteServiceCaller(invoker, dns)
    Repo->>RSC: Invoke(ctx, fullMethod, req, resp)

    RSC->>UI: Invoke(ctx, dns, fullMethod, req, resp)
    UI->>UI: 复用 incoming/outgoing metadata
    UI->>UI: 注入 ServiceAppId / ServiceInstanceId
    UI->>UI: 基于统一 timeout 构造 outgoing ctx
    UI->>CM: Dial(ctx, dns)
    CM->>DM: Build(dns)
    DM->>DM: Normalize + Validate
    DM-->>CM: Target(dns:///service.namespace.svc.cluster.local:port)
    CM->>CM: 按最终 gRPC target 查连接缓存
    alt 命中缓存
        CM-->>UI: 复用现有 grpc.ClientConn
    else 未命中
        CM->>RT: grpc.NewClient(target)
        RT-->>CM: 建立连接
        CM-->>UI: 返回新连接
    end

    UI->>RT: conn.Invoke(outgoing ctx, fullMethod, req, resp)
    RT->>Down: 路由到目标业务服务
    Down-->>RT: resp
    RT-->>UI: resp
    UI-->>RSC: 返回结果
    RSC-->>Repo: 返回结果

示例

package example

import (
	"context"
	"time"

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

func Example() error {
	dnsManager := invocation.NewDNSManager(&invocation.DNSConfig{
		DefaultNamespace: "default",
		DefaultPort:      9090,
	})

	manager, err := invocation.NewConnectionManager(invocation.ConnectionManagerOptions{
		DNSManager: dnsManager,
	})
	if err != nil {
		return err
	}
	defer func() { _ = manager.Close() }()

	services := invocation.NewRemoteServiceManaged(
		invocation.NewUnaryInvoker(manager, "config", "config-1", 3*time.Second),
		service.DNS{
			Service: "auth",
		},
	)

	caller, err := services.Caller("auth")
	if err != nil {
		return err
	}

	return caller.Invoke(
		context.Background(),
		"/acme.auth.app.v1.AuthAppService/GetAppSecret",
		&struct{}{},
		&struct{}{},
	)
}

如果 repo 层已经明确绑定某个远程业务服务,也可以直接构造单服务 caller:

package example

import (
	"context"
	"time"

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

func ExampleSingleCaller() error {
	dnsManager := invocation.NewDNSManager(&invocation.DNSConfig{
		DefaultNamespace: "default",
		DefaultPort:      9090,
	})

	manager, err := invocation.NewConnectionManager(invocation.ConnectionManagerOptions{
		DNSManager: dnsManager,
	})
	if err != nil {
		return err
	}
	defer func() { _ = manager.Close() }()

	caller := invocation.NewRemoteServiceCaller(
		invocation.NewUnaryInvoker(manager, "config", "config-1", 3*time.Second),
		&service.DNS{
			Service: "auth",
		},
	)
	return caller.Invoke(
		context.Background(),
		"/acme.auth.app.v1.AuthAppService/GetAppSecret",
		&struct{}{},
		&struct{}{},
	)
}

观测约定

invocation 默认和 go-micro 的 OTel 链路保持一致:

  • gRPC client 默认挂 otelgrpc
  • 出站 metadata 由 UnaryInvoker 基于当前链路 metadata 与服务自身身份统一构造

设计约束

  • 业务侧只表达业务服务 DNS,不表达实例选择逻辑
  • invocation 只保留通用调用语义,不承载后端专属实现
  • RemoteServiceCaller 只做样板代码收口,不替代 UnaryInvoker
  • go-consul/invocationgo-k8s/invocation 不再作为主路径保留

Documentation

Overview

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

Index

Constants

View Source
const (
	// DefaultServiceType 是 Kubernetes Service FQDN 中的固定服务类型片段。
	DefaultServiceType = "svc"
	// DefaultClusterDomain 是 Kubernetes 集群默认的 Cluster Domain。
	DefaultClusterDomain = "cluster.local"
	// DefaultResolverScheme 是 gRPC 默认推荐使用的 DNS resolver scheme。
	DefaultResolverScheme = "dns"
	// 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 负责缓存基于 service.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 *svc.DNS) (*grpc.ClientConn, error)

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

连接缓存键采用最终 gRPC target,而不是 service.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 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 负责把结构化的 service.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 *svc.DNS) (*Target, error)

Build 根据 service.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 *svc.DNS) *svc.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 *svc.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 *svc.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 *svc.DNS
	// Invoker 负责统一的连接获取、metadata 注入和实际调用。
	//
	// 当前约束下 RemoteServiceCaller 只是一个薄封装,
	// 真正的调用行为仍全部落在 UnaryInvoker 上。
	Invoker *UnaryInvoker
}

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

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

例如: - auth 业务服务

  • AuthAppService
  • AuthUserService
  • AuthPermissionService

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

func NewRemoteServiceCaller added in v1.3.9

func NewRemoteServiceCaller(invoker *UnaryInvoker, dns *svc.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

其余通用逻辑由 service.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 ...svc.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) (*svc.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. 基于 service.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 *svc.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