Refactor: remove config in grpc and dubbo3#3231
Refactor: remove config in grpc and dubbo3#3231Snow-kal wants to merge 17 commits intoapache:developfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR continues the config-package removal effort (issues #2741 / #3204) by refactoring the gRPC and Dubbo3 (triple) protocol implementations to source runtime behavior from global.* defaults and URL attributes instead of config/*.
Changes:
- Remove legacy
configcompatibility branches for TLS/service/protocol/tracing in gRPC client/server. - Refactor Dubbo3 protocol/invoker to read timeout, tracing, TLS, and service instances from
URLattributes (with some type checks and fallbacks). - Clean up deprecated/compat code paths and related imports.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
protocol/grpc/server.go |
Drops config-based provider/TLS lookup; relies on URL attributes and global TLS helpers. |
protocol/grpc/client.go |
Drops config-based TLS/protocol/service lookup; uses URL attributes and safer invoker reflection handling. |
protocol/dubbo3/dubbo3_protocol.go |
Removes config dependency; tracing/TLS/service resolved from URL attributes. |
protocol/dubbo3/dubbo3_invoker.go |
Removes config dependency; timeout/tracing/TLS/service resolved from global + URL attributes. |
Comments suppressed due to low confidence (4)
protocol/grpc/server.go:114
- In Start(), if TLSConfigKey is present but not a *global.TLSConfig, the function returns early after net.Listen() without closing the listener, and the server never starts. Consider logging the type assertion failure and continuing with the already-configured insecure creds (or explicitly closing lis before returning) to avoid leaking the bound port.
if tlsConfRaw, ok := url.GetAttribute(constant.TLSConfigKey); ok {
// use global TLSConfig handle tls
tlsConf, ok := tlsConfRaw.(*global.TLSConfig)
if !ok {
logger.Errorf("gRPC Server initialized the TLSConfig configuration failed")
return
}
protocol/grpc/server.go:155
- getProviderServices() returns nil when ProviderConfigKey is missing/invalid, but Start() has already created the listener and server and the goroutine will exit early, leaving the listener bound with no serving loop. To avoid leaking resources / hanging startup, consider either: (1) moving net.Listen()/grpc.NewServer() until after provider services are validated, (2) returning an empty map and allowing Serve() to run, or (3) explicitly closing the listener and stopping the server on this error path.
// getProviderServices retrieves provider services from URL attributes.
func getProviderServices(url *common.URL) map[string]*global.ServiceConfig {
if providerConfRaw, ok := url.GetAttribute(constant.ProviderConfigKey); ok {
if providerConf, ok := providerConfRaw.(*global.ProviderConfig); ok && providerConf != nil {
return providerConf.Services
}
logger.Error("illegal provider config")
}
return nil
}
protocol/grpc/client.go:100
- The returned error message uses "DUBBO3 Client ..." even though this is the gRPC client path, and it doesn't match the preceding log line. Please align the error text with the component (gRPC) so users can diagnose mis-typed TLSConfigKey attributes more easily.
tlsConf, ok := tlsConfRaw.(*global.TLSConfig)
if !ok {
logger.Errorf("Grpc Client initialized the TLSConfig configuration failed")
return nil, errors.New("DUBBO3 Client initialized the TLSConfig configuration failed")
}
protocol/dubbo3/dubbo3_invoker.go:87
- NewDubboInvoker() now relies solely on url attribute RpcServiceKey for consumerService, but it can remain nil when the attribute isn't set; that nil is then passed into triple.NewTripleClient(). Adding an explicit check with a clear error (including interface/service key) before constructing the client would make failures deterministic and easier to debug.
timeout := url.GetParamDuration(constant.TimeoutKey, rt)
// for triple pb serialization. The bean name from provider is the provider reference key,
// which can't locate the target consumer stub, so we use interface key.
consumerService = nil
if rpcService, ok := url.GetAttribute(constant.RpcServiceKey); ok {
consumerService = rpcService
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Codecov Report❌ Patch coverage is Additional details and impacted files☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
protocol/dubbo3/dubbo3_protocol.go
Outdated
| service = rpcService | ||
| } | ||
| if service == nil { | ||
| logger.Errorf("no rpc service found in url attribute %s for service key: %s", constant.RpcServiceKey, key) |
There was a problem hiding this comment.
| logger.Errorf("no rpc service found in url attribute %s for service key: %s", constant.RpcServiceKey, key) | |
| logger.Errorf("[Triple Protocol] No rpc service found in url attribute %s for service key: %s", constant.RpcServiceKey, key) |
| @@ -139,12 +121,7 @@ func (s *Server) Start(url *common.URL) { | |||
| logger.Infof("gRPC Server initialized the TLSConfig configuration") | |||
| serverOpts = append(serverOpts, grpc.Creds(credentials.NewTLS(cfg))) | |||
| } | |||
| } else { | |||
| serverOpts = append(serverOpts, grpc.Creds(insecure.NewCredentials())) | |||
| } | |||
| } else { | |||
| // TODO: remove this else | |||
| serverOpts = append(serverOpts, grpc.Creds(insecure.NewCredentials())) | |||
| } | |||
There was a problem hiding this comment.
这里不应该是有TLSConfigKey的时候append credentials.NewTLS(cfg),没有的时候grpc.Creds(insecure.NewCredentials())吗
现在的逻辑是有没有都grpc.Creds(insecure.NewCredentials())
There was a problem hiding this comment.
protocol/grpc/client.go
Outdated
| @@ -127,12 +108,7 @@ func NewClient(url *common.URL) (*Client, error) { | |||
| logger.Infof("Grpc Client initialized the TLSConfig configuration") | |||
| dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(cfg))) | |||
| } | |||
| } else { | |||
| dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) | |||
| } | |||
| } else { | |||
| // TODO: remove this else | |||
| dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) | |||
| } | |||
There was a problem hiding this comment.
已经更改 感谢建议 这个和以上的 server 的类似

总结一下就是
transportCreds = insecure.NewCredentials() // 默认值:无 TLS
if url 有 TLSConfigKey {
if tlsConf 类型断言失败 {
return error // 配置异常,直接返回
}
if IsClientTLSValid(tlsConf) {
if GetClientTlSConfig 出错 {
return error // 获取 TLS 配置失败,直接返回
}
if cfg != nil {
transportCreds = credentials.NewTLS(cfg) // 覆盖为 TLS
}
}
}
dialOpts = append(dialOpts, grpc.WithTransportCredentials(transportCreds)) // 只 append 一次
| if rpcService, ok := url.GetAttribute(constant.RpcServiceKey); ok { | ||
| consumerService = rpcService | ||
| } | ||
| var consumerService any |
There was a problem hiding this comment.
请问一下是改成
var consumerService any = nil这个意思吗
现在的 var consumerService any 零值就是 nil
还是别的意思
AlexStocks
left a comment
There was a problem hiding this comment.
阻塞问题:
- protocol/grpc/client.go 在 getInvoker 返回 nil 时仍返回可用 client,对应 invoker 是零值 reflect.Value,后续调用会在运行时 panic。这里应该直接返回 error,不要延迟失败。
- TLS 逻辑默认先 append insecure credentials,再尝试 append TLS。现在语义上是 fail-open,TLS 属性缺失/类型错误时会静默回落明文,风险高。建议改成互斥分支:有合法 TLS 就只用 TLS;配置声明 TLS 但构造失败时直接失败。
protocol/grpc/client.go
Outdated
| grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize), | ||
| grpc.MaxCallSendMsgSize(maxCallSendMsgSize), | ||
| ), | ||
| grpc.WithTransportCredentials(insecure.NewCredentials()), |
There was a problem hiding this comment.
insecure.NewCredentials() 被无条件加入 dialOpts,之后若命中 TLS 分支,又 append 了 credentials.NewTLS(cfg)。gRPC 不允许同一连接同时配置两套 transport credentials,TLS 场景完全失效。原代码是互斥的 else if ... else 结构,PR 把互斥性破坏了。server.go 存在同样问题。
建议恢复互斥结构:
if tlsConfRaw, ok := url.GetAttribute(constant.TLSConfigKey); ok {
// TLS 路径
} else {
dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials()))
}
There was a problem hiding this comment.
var transportCreds credentials.TransportCredentials
transportCreds = insecure.NewCredentials() // 默认值
if url 有 TLSConfigKey && TLS 有效 && cfg != nil {
transportCreds = credentials.NewTLS(cfg) // 覆盖,不是 append
}
dialOpts = append(dialOpts, grpc.WithTransportCredentials(transportCreds)) // 只 append 一次
如果不行的话我就直接改回去了
| if rpcService, ok := url.GetAttribute(constant.RpcServiceKey); ok { | ||
| consumerService = rpcService | ||
| } | ||
| invoker := getInvoker(consumerService, conn) |
There was a problem hiding this comment.
getInvoker 内部:reflect.ValueOf(nil).MethodByName("GetDubboStub") 当 consumerService 为 nil 时会直接 panic,根本不会返回 nil 供调用方检查。if invoker != nil 这个 nil guard 加在 panic 之后,毫无意义。另外返回 reflect.Value{} 后续调用 invoker.Call(...) 同样会 panic。
建议:在调用 getInvoker 前检查:
if consumerService == nil {
conn.Close()
return nil, fmt.Errorf("grpc: no rpc service found for interface=%s", key)
}
protocol/dubbo3/dubbo3_protocol.go
Outdated
| } | ||
| if service == nil { | ||
| logger.Errorf("no rpc service found in url attribute %s for service key: %s", constant.RpcServiceKey, key) | ||
| return nil |
There was a problem hiding this comment.
Export 提前 return nil 导致 exporter 没有写入 map,grpc/server.go 的 waitGrpcExporter 会等待 exporter 数量与 providerServices 数量一致,因超时最终触发 panic("wait grpc exporter timeout"),真正原因(缺少 RpcServiceKey)被完全隐藏,排查极难。
调用方(server/action.go、config/service_config.go)会把 nil 当错误向上传递,但中间层 filter chain 不一定做了 nil 检查,存在隐患。
| ) | ||
| // TODO: Temporary compatibility with old APIs, can be removed later | ||
| rt = config.GetConsumerConfig().RequestTimeout | ||
| rt = global.DefaultConsumerConfig().RequestTimeout |
There was a problem hiding this comment.
原来 config.GetConsumerConfig().RequestTimeout 若无配置返回空字符串,由 url.GetParamDuration 处理默认值,用户可以明确禁用超时(传零值)。改成 global.DefaultConsumerConfig().RequestTimeout 后始终是 "3s",超时无法被禁用,语义变了。
建议:先检查 ConsumerConfig attribute 是否存在,不存在时才使用 DefaultConsumerConfig()。
There was a problem hiding this comment.
感谢建议 目前已经是这个逻辑了 可以看看是否有问题
rt = global.DefaultConsumerConfig().RequestTimeout // 先用默认值 "3s"
if consumerConfRaw, ok := url.GetAttribute(constant.ConsumerConfigKey); ok {
if consumerConf, ok := consumerConfRaw.(*global.ConsumerConfig); ok {
rt = consumerConf.RequestTimeout // 有用户配置则覆盖
}
}
protocol/grpc/server.go
Outdated
| } | ||
|
|
||
| ds.SetProxyImpl(invoker) | ||
| server.RegisterService(ds.ServiceDesc(), service) |
There was a problem hiding this comment.
类型断言 ds, ok := service.(DubboGrpcService) 已经得到了 ds,但最终传给 server.RegisterService 的仍是 service(类型 any)而非 ds。gRPC 的 RegisterService 需要第二个参数满足 service descriptor handler 签名,传 any 类型不一定满足,运行时可能失败。原代码传的是经过 config.GetProviderService(key) 拿到的具体对象,类型一致性有保障。
建议改为:
server.RegisterService(ds.ServiceDesc(), ds)
protocol/grpc/client.go
Outdated
| } else { | ||
| logger.Warnf("grpc client invoker is nil, interface=%s", key) | ||
| } |
There was a problem hiding this comment.
logger只能记录,程序在初始化 invoker(RPC 调用执行器)时发现对象为 nil应该终止,返回 error,阻止 Client 被创建。
protocol/grpc/client.go
Outdated
| if invoker != nil { | ||
| invokerValue = reflect.ValueOf(invoker) | ||
| } else { | ||
| logger.Warnf("grpc client invoker is nil, interface=%s", key) |
There was a problem hiding this comment.
| logger.Warnf("grpc client invoker is nil, interface=%s", key) | |
| err := fmt.Errorf("grpc client invoker is nil, interface=%s", key) | |
| logger.Errorf("failed to get grpc client invoker: %v", err) | |
| return nil, err |
nanjiek
left a comment
There was a problem hiding this comment.
核心环节须 Fail-fast,严禁带着错误状态继续运行触发 Panic。
|







更改概览和 TODO 更改情况
protocol/dubbo3/dubbo3_invoker.go 已移除
protocol/dubbo3/dubbo3_protocol.go 已移除
protocol/grpc/client.go 已移除
protocol/grpc/server.go 已移除
Description
issue #3204
Checklist
develop