Copilot commented on code in PR #862:
URL: https://github.com/apache/dubbo-go-pixiu/pull/862#discussion_r3084090331


##########
go.mod:
##########
@@ -4,7 +4,7 @@ go 1.25
 
 require (
        dario.cat/mergo v1.0.1
-       dubbo.apache.org/dubbo-go/v3 v3.3.1
+       dubbo.apache.org/dubbo-go/v3 v3.0.0-20260210015753-35ea886421f9
        github.com/IBM/sarama v1.45.1

Review Comment:
   PR description says the client is updated to "latest dubbo-go v3.3.1", but 
`go.mod` pins `dubbo.apache.org/dubbo-go/v3` to the pseudo-version 
`v3.0.0-20260210015753-35ea886421f9` instead. Please align the dependency 
version with the PR description (or update the description and rationale if 
this pseudo-version is required).



##########
pkg/client/dubbo/dubbo.go:
##########
@@ -289,79 +354,342 @@ func (dc *Client) check(key string) bool {
        return false
 }
 
-// Get find a dubbo GenericService
-func (dc *Client) Get(ir config.IntegrationRequest) *generic.GenericService {
-       key := apiKey(&ir)
-       if dc.check(key) {
-               return dc.get(key)
+func (dc *Client) resolveReferSpec(irequest config.IntegrationRequest) 
(resolvedReferSpec, error) {
+       spec := resolvedReferSpec{
+               Interface:        irequest.Interface,
+               Group:            irequest.Group,
+               Version:          irequest.Version,
+               ConsumerDefaults: dc.resolveConsumerDefaults(irequest),
        }
 
-       return dc.create(key, ir)
-}
+       if len(dc.registries) > 0 {
+               registryIDs := make([]string, 0, len(dc.registries))
+               useNacosWarmup := false
+               for id, registry := range dc.registries {
+                       registryIDs = append(registryIDs, id)
+                       if registry != nil && registry.Protocol == "nacos" {
+                               useNacosWarmup = true
+                       }
+               }
+               sort.Strings(registryIDs)
+               spec.Mode = "registry"
+               spec.RegistryIDs = registryIDs
+               spec.UseNacosWarmup = useNacosWarmup
+               spec.EffectiveProtocol = resolveDeclaredProtocol(irequest)
+               return spec, nil
+       }
 
-func apiKey(ir *config.IntegrationRequest) string {
-       dbc := ir.DubboBackendConfig
-       return strings.Join([]string{dbc.ClusterName, dbc.ApplicationName, 
dbc.Interface, dbc.Version, dbc.Group}, "_")
+       canonicalURL := strings.TrimSpace(irequest.URL)
+       if canonicalURL == "" {
+               return resolvedReferSpec{}, errors.New("dubbo refer mode 
invalid: no registry configured and no direct url provided")
+       }
+       directProtocol, err := directURLProtocol(canonicalURL)
+       if err != nil {
+               return resolvedReferSpec{}, err
+       }
+
+       spec.Mode = "direct"
+       spec.URL = canonicalURL
+       spec.EffectiveProtocol = directProtocol
+       return spec, nil
 }
 
-func (dc *Client) create(key string, irequest config.IntegrationRequest) 
*generic.GenericService {
-       useNacosRegister := false
-       registerIds := make([]string, 0)
-       for k, v := range dc.rootConfig.Registries {
-               registerIds = append(registerIds, k)
-               if v.Protocol == "nacos" {
-                       useNacosRegister = true
+func (dc *Client) resolveConsumerDefaults(irequest config.IntegrationRequest) 
resolvedConsumerDefaults {
+       defaults := resolvedConsumerDefaults{
+               Cluster: "failover",
+               Retries: "3",
+       }
+
+       if dc.dubboProxyConfig == nil {
+               if strings.TrimSpace(irequest.Retries) != "" {
+                       defaults.Retries = strings.TrimSpace(irequest.Retries)
                }
+               defaults.RequestTimeout = cst.DefaultReqTimeout
+               return defaults
        }
 
-       refConf := dg.ReferenceConfig{
-               InterfaceName: irequest.Interface,
-               Cluster:       constant.ClusterKeyFailover,
-               RegistryIDs:   registerIds,
-               Protocol:      dubbo.DUBBO,
-               Generic:       "true",
-               Version:       irequest.Version,
-               Group:         irequest.Group,
-               Loadbalance:   dc.dubboProxyConfig.LoadBalance,
-               Retries:       dc.dubboProxyConfig.Retries,
+       defaults.LoadBalance = dc.dubboProxyConfig.LoadBalance
+       if strings.TrimSpace(dc.dubboProxyConfig.Retries) != "" {
+               defaults.Retries = 
strings.TrimSpace(dc.dubboProxyConfig.Retries)
+       } else if strings.TrimSpace(irequest.Retries) != "" {
+               defaults.Retries = strings.TrimSpace(irequest.Retries)
        }
 
-       if refConf.Retries == "" {
-               if len(irequest.Retries) == 0 {
-                       refConf.Retries = "3"
+       if dc.dubboProxyConfig.Timeout != nil {
+               if timeout, err := 
time.ParseDuration(dc.dubboProxyConfig.Timeout.RequestTimeoutStr); err == nil {
+                       defaults.RequestTimeout = timeout
                } else {
-                       refConf.Retries = irequest.Retries
+                       defaults.RequestTimeout = cst.DefaultReqTimeout
                }
+       } else {
+               defaults.RequestTimeout = cst.DefaultReqTimeout
        }
 
-       if dc.dubboProxyConfig.Timeout != nil {
-               refConf.RequestTimeout = 
dc.dubboProxyConfig.Timeout.RequestTimeoutStr
-       } else {
-               refConf.RequestTimeout = cst.DefaultReqTimeout.String()
+       return defaults
+}
+
+func (spec resolvedReferSpec) validate() error {
+       switch spec.Mode {
+       case "registry":
+               if len(spec.RegistryIDs) == 0 {
+                       return errors.New("dubbo refer mode invalid: registry 
mode requires registry ids")
+               }
+               return nil
+       case "direct":
+               if strings.TrimSpace(spec.URL) == "" {
+                       return errors.New("dubbo refer mode invalid: direct 
mode requires direct url")
+               }
+               return nil
+       default:
+               return errors.Errorf("dubbo refer mode invalid: %s", spec.Mode)
+       }
+}
+
+func (spec resolvedReferSpec) cacheKey() (string, error) {
+       if err := spec.validate(); err != nil {
+               return "", err
+       }
+
+       key := spec.genericServiceKey()
+       raw, err := json.Marshal(key)
+       if err != nil {
+               return "", errors.Wrap(err, "marshal generic service key")
+       }
+       return string(raw), nil
+}
+
+func (spec resolvedReferSpec) genericServiceKey() genericServiceKey {
+       registryIDs := append([]string(nil), spec.RegistryIDs...)
+       sort.Strings(registryIDs)
+       return genericServiceKey{
+               Mode:              spec.Mode,
+               URL:               spec.URL,
+               RegistryIDs:       registryIDs,
+               Cluster:           spec.ConsumerDefaults.Cluster,
+               Interface:         spec.Interface,
+               Version:           spec.Version,
+               Group:             spec.Group,
+               EffectiveProtocol: spec.EffectiveProtocol,
+       }
+}
+
+// Get find a dubbo GenericService
+func (dc *Client) Get(spec resolvedReferSpec) (*generic.GenericService, error) 
{
+       key, err := spec.cacheKey()
+       if err != nil {
+               return nil, err
+       }
+       if dc.check(key) {
+               return dc.get(key), nil
+       }
+
+       return dc.create(spec)
+}
+
+func (dc *Client) create(spec resolvedReferSpec) (*generic.GenericService, 
error) {
+       if err := spec.validate(); err != nil {
+               return nil, err
+       }
+       if dc.dubboClient == nil {
+               return nil, errors.New("dubbo client is not initialized, call 
Apply() first")
+       }
+
+       key, err := spec.cacheKey()
+       if err != nil {
+               return nil, err
+       }
+
+       opts, err := dc.buildReferenceOptions(spec)
+       if err != nil {
+               return nil, err
        }
-       logger.Debugf("[dubbo-go-pixiu] client dubbo timeout val %v", 
refConf.RequestTimeout)
+
        dc.lock.Lock()
        defer dc.lock.Unlock()
 
        if service, ok := dc.GenericServicePool[key]; ok {
-               return service
+               return service, nil
        }
 
-       if err := dg.Load(dg.WithRootConfig(dc.rootConfig)); err != nil {
-               panic(err)
+       clientService, err := dc.dubboClient.NewGenericService(spec.Interface, 
opts...)
+       if err != nil {
+               return nil, err
        }
 
-       _ = refConf.Init(dc.rootConfig)
-       refConf.GenericLoad(key)
-
-       // sleep when first call to fetch enough service meta data from nacos
-       // todo: GenericLoad should guarantee it
-       if useNacosRegister {
-               time.Sleep(1000 * time.Millisecond)
+       if spec.Mode == "registry" && spec.UseNacosWarmup {
+               time.Sleep(time.Second)
        }

Review Comment:
   `create` holds `dc.lock` while calling 
`dc.dubboClient.NewGenericService(...)` and also while doing the Nacos warmup 
`time.Sleep(time.Second)`. This blocks all concurrent lookups/creations in 
`GenericServicePool` for up to 1s and can become a latency/throughput 
bottleneck. Consider narrowing the critical section (double-check cache under 
lock, create outside the lock, then lock again to publish) and ensure any 
warmup sleep happens outside the mutex.



##########
pkg/client/dubbo/dubbo.go:
##########
@@ -289,79 +354,342 @@ func (dc *Client) check(key string) bool {
        return false
 }
 
-// Get find a dubbo GenericService
-func (dc *Client) Get(ir config.IntegrationRequest) *generic.GenericService {
-       key := apiKey(&ir)
-       if dc.check(key) {
-               return dc.get(key)
+func (dc *Client) resolveReferSpec(irequest config.IntegrationRequest) 
(resolvedReferSpec, error) {
+       spec := resolvedReferSpec{
+               Interface:        irequest.Interface,
+               Group:            irequest.Group,
+               Version:          irequest.Version,
+               ConsumerDefaults: dc.resolveConsumerDefaults(irequest),
        }
 
-       return dc.create(key, ir)
-}
+       if len(dc.registries) > 0 {
+               registryIDs := make([]string, 0, len(dc.registries))
+               useNacosWarmup := false
+               for id, registry := range dc.registries {
+                       registryIDs = append(registryIDs, id)
+                       if registry != nil && registry.Protocol == "nacos" {
+                               useNacosWarmup = true
+                       }
+               }
+               sort.Strings(registryIDs)
+               spec.Mode = "registry"
+               spec.RegistryIDs = registryIDs
+               spec.UseNacosWarmup = useNacosWarmup
+               spec.EffectiveProtocol = resolveDeclaredProtocol(irequest)
+               return spec, nil
+       }
 
-func apiKey(ir *config.IntegrationRequest) string {
-       dbc := ir.DubboBackendConfig
-       return strings.Join([]string{dbc.ClusterName, dbc.ApplicationName, 
dbc.Interface, dbc.Version, dbc.Group}, "_")
+       canonicalURL := strings.TrimSpace(irequest.URL)
+       if canonicalURL == "" {
+               return resolvedReferSpec{}, errors.New("dubbo refer mode 
invalid: no registry configured and no direct url provided")
+       }
+       directProtocol, err := directURLProtocol(canonicalURL)
+       if err != nil {
+               return resolvedReferSpec{}, err
+       }
+
+       spec.Mode = "direct"
+       spec.URL = canonicalURL
+       spec.EffectiveProtocol = directProtocol
+       return spec, nil
 }
 
-func (dc *Client) create(key string, irequest config.IntegrationRequest) 
*generic.GenericService {
-       useNacosRegister := false
-       registerIds := make([]string, 0)
-       for k, v := range dc.rootConfig.Registries {
-               registerIds = append(registerIds, k)
-               if v.Protocol == "nacos" {
-                       useNacosRegister = true
+func (dc *Client) resolveConsumerDefaults(irequest config.IntegrationRequest) 
resolvedConsumerDefaults {
+       defaults := resolvedConsumerDefaults{
+               Cluster: "failover",
+               Retries: "3",
+       }
+
+       if dc.dubboProxyConfig == nil {
+               if strings.TrimSpace(irequest.Retries) != "" {
+                       defaults.Retries = strings.TrimSpace(irequest.Retries)
                }
+               defaults.RequestTimeout = cst.DefaultReqTimeout
+               return defaults
        }
 
-       refConf := dg.ReferenceConfig{
-               InterfaceName: irequest.Interface,
-               Cluster:       constant.ClusterKeyFailover,
-               RegistryIDs:   registerIds,
-               Protocol:      dubbo.DUBBO,
-               Generic:       "true",
-               Version:       irequest.Version,
-               Group:         irequest.Group,
-               Loadbalance:   dc.dubboProxyConfig.LoadBalance,
-               Retries:       dc.dubboProxyConfig.Retries,
+       defaults.LoadBalance = dc.dubboProxyConfig.LoadBalance
+       if strings.TrimSpace(dc.dubboProxyConfig.Retries) != "" {
+               defaults.Retries = 
strings.TrimSpace(dc.dubboProxyConfig.Retries)
+       } else if strings.TrimSpace(irequest.Retries) != "" {
+               defaults.Retries = strings.TrimSpace(irequest.Retries)
        }
 
-       if refConf.Retries == "" {
-               if len(irequest.Retries) == 0 {
-                       refConf.Retries = "3"
+       if dc.dubboProxyConfig.Timeout != nil {
+               if timeout, err := 
time.ParseDuration(dc.dubboProxyConfig.Timeout.RequestTimeoutStr); err == nil {
+                       defaults.RequestTimeout = timeout
                } else {
-                       refConf.Retries = irequest.Retries
+                       defaults.RequestTimeout = cst.DefaultReqTimeout
                }
+       } else {
+               defaults.RequestTimeout = cst.DefaultReqTimeout
        }
 
-       if dc.dubboProxyConfig.Timeout != nil {
-               refConf.RequestTimeout = 
dc.dubboProxyConfig.Timeout.RequestTimeoutStr
-       } else {
-               refConf.RequestTimeout = cst.DefaultReqTimeout.String()
+       return defaults
+}
+
+func (spec resolvedReferSpec) validate() error {
+       switch spec.Mode {
+       case "registry":
+               if len(spec.RegistryIDs) == 0 {
+                       return errors.New("dubbo refer mode invalid: registry 
mode requires registry ids")
+               }
+               return nil
+       case "direct":
+               if strings.TrimSpace(spec.URL) == "" {
+                       return errors.New("dubbo refer mode invalid: direct 
mode requires direct url")
+               }
+               return nil
+       default:
+               return errors.Errorf("dubbo refer mode invalid: %s", spec.Mode)
+       }
+}
+
+func (spec resolvedReferSpec) cacheKey() (string, error) {
+       if err := spec.validate(); err != nil {
+               return "", err
+       }
+
+       key := spec.genericServiceKey()
+       raw, err := json.Marshal(key)
+       if err != nil {
+               return "", errors.Wrap(err, "marshal generic service key")
+       }
+       return string(raw), nil
+}
+
+func (spec resolvedReferSpec) genericServiceKey() genericServiceKey {
+       registryIDs := append([]string(nil), spec.RegistryIDs...)
+       sort.Strings(registryIDs)
+       return genericServiceKey{
+               Mode:              spec.Mode,
+               URL:               spec.URL,
+               RegistryIDs:       registryIDs,
+               Cluster:           spec.ConsumerDefaults.Cluster,
+               Interface:         spec.Interface,
+               Version:           spec.Version,
+               Group:             spec.Group,
+               EffectiveProtocol: spec.EffectiveProtocol,
+       }
+}
+
+// Get find a dubbo GenericService
+func (dc *Client) Get(spec resolvedReferSpec) (*generic.GenericService, error) 
{
+       key, err := spec.cacheKey()
+       if err != nil {
+               return nil, err
+       }
+       if dc.check(key) {
+               return dc.get(key), nil
+       }
+
+       return dc.create(spec)
+}
+
+func (dc *Client) create(spec resolvedReferSpec) (*generic.GenericService, 
error) {
+       if err := spec.validate(); err != nil {
+               return nil, err
+       }
+       if dc.dubboClient == nil {
+               return nil, errors.New("dubbo client is not initialized, call 
Apply() first")
+       }
+
+       key, err := spec.cacheKey()
+       if err != nil {
+               return nil, err
+       }
+
+       opts, err := dc.buildReferenceOptions(spec)
+       if err != nil {
+               return nil, err
        }
-       logger.Debugf("[dubbo-go-pixiu] client dubbo timeout val %v", 
refConf.RequestTimeout)
+
        dc.lock.Lock()
        defer dc.lock.Unlock()
 
        if service, ok := dc.GenericServicePool[key]; ok {
-               return service
+               return service, nil
        }
 
-       if err := dg.Load(dg.WithRootConfig(dc.rootConfig)); err != nil {
-               panic(err)
+       clientService, err := dc.dubboClient.NewGenericService(spec.Interface, 
opts...)
+       if err != nil {
+               return nil, err
        }
 
-       _ = refConf.Init(dc.rootConfig)
-       refConf.GenericLoad(key)
-
-       // sleep when first call to fetch enough service meta data from nacos
-       // todo: GenericLoad should guarantee it
-       if useNacosRegister {
-               time.Sleep(1000 * time.Millisecond)
+       if spec.Mode == "registry" && spec.UseNacosWarmup {
+               time.Sleep(time.Second)
        }
 
-       clientService := refConf.GetRPCService().(*generic.GenericService)
        dc.GenericServicePool[key] = clientService
 
-       return clientService
+       return clientService, nil
+}
+
+// buildReferenceOptions builds a list of dubbo-go ReferenceOption using the 
official API.
+func (dc *Client) buildReferenceOptions(spec resolvedReferSpec) 
([]dclient.ReferenceOption, error) {
+       if err := spec.validate(); err != nil {
+               return nil, err
+       }
+       if strings.TrimSpace(spec.EffectiveProtocol) == "" {
+               return nil, errors.New("dubbo refer mode invalid: effective 
protocol is required")
+       }
+
+       defaults := spec.ConsumerDefaults
+       opts := make([]dclient.ReferenceOption, 0, 16)
+
+       opts = append(opts, dclient.WithInterface(spec.Interface))
+       if spec.Group != "" {
+               opts = append(opts, dclient.WithGroup(spec.Group))
+       }
+       if spec.Version != "" {
+               opts = append(opts, dclient.WithVersion(spec.Version))
+       }
+
+       opts = appendModeReferenceOptions(opts, spec)
+       opts = append(opts, clusterReferenceOption(defaults.Cluster))
+       opts = append(opts, protocolReferenceOption(spec.EffectiveProtocol))
+
+       if loadBalanceOpt := loadBalanceReferenceOption(defaults.LoadBalance); 
loadBalanceOpt != nil {
+               opts = append(opts, loadBalanceOpt)
+       }
+
+       retries := 3
+       if strings.TrimSpace(defaults.Retries) != "" {
+               if resolvedRetries, err := strconv.Atoi(defaults.Retries); err 
== nil {
+                       retries = resolvedRetries
+               }
+       }
+       opts = append(opts, dclient.WithRetries(retries))
+
+       timeout := defaults.RequestTimeout
+       if timeout <= 0 {
+               timeout = cst.DefaultReqTimeout
+       }
+       opts = append(opts, dclient.WithRequestTimeout(timeout))
+
+       opts = append(opts, dclient.WithGeneric())
+
+       return opts, nil
+}
+
+func appendModeReferenceOptions(opts []dclient.ReferenceOption, spec 
resolvedReferSpec) []dclient.ReferenceOption {
+       switch spec.Mode {
+       case "registry":
+               registryIDs := append([]string(nil), spec.RegistryIDs...)
+               sort.Strings(registryIDs)
+               return append(opts, dclient.WithRegistryIDs(registryIDs...))
+       case "direct":
+               return append(opts, dclient.WithURL(spec.URL))
+       default:
+               return opts
+       }
+}
+
+func clusterReferenceOption(cluster string) dclient.ReferenceOption {
+       switch cluster {
+       case "failover":
+               return dclient.WithClusterFailOver()
+       case "failfast":
+               return dclient.WithClusterFailFast()
+       case "failsafe":
+               return dclient.WithClusterFailSafe()
+       case "failback":
+               return dclient.WithClusterFailBack()
+       case "broadcast":
+               return dclient.WithClusterBroadcast()
+       case "forking":
+               return dclient.WithClusterForking()
+       case "available":
+               return dclient.WithClusterAvailable()
+       case "zoneaware":
+               return dclient.WithClusterZoneAware()
+       case "adaptiveservice":
+               return dclient.WithClusterAdaptiveService()
+       default:
+               return dclient.WithCluster(cluster)
+       }
+}
+
+func protocolReferenceOption(protocol string) dclient.ReferenceOption {
+       switch protocol {
+       case "tri", "triple":
+               return dclient.WithProtocolTriple()
+       case "dubbo":
+               return dclient.WithProtocolDubbo()
+       case "jsonrpc":
+               return dclient.WithProtocolJsonRPC()
+       default:
+               return dclient.WithProtocol(protocol)
+       }
+}
+
+func loadBalanceReferenceOption(loadBalance string) dclient.ReferenceOption {
+       switch loadBalance {
+       case "":
+               return nil
+       case "random":
+               return dclient.WithLoadBalanceRandom()
+       case "roundrobin":
+               return dclient.WithLoadBalanceRoundRobin()
+       case "leastactive":
+               return dclient.WithLoadBalanceLeastActive()
+       case "consistenthash", "consistenthashing":
+               return dclient.WithLoadBalanceConsistentHashing()
+       case "p2c":
+               return dclient.WithLoadBalanceP2C()
+       default:
+               return dclient.WithLoadBalance(loadBalance)
+       }
+}
+
+func resolveDeclaredProtocol(irequest config.IntegrationRequest) string {
+       if protocol := normalizeReferenceProtocol(irequest.Protocol); protocol 
!= "" {
+               return protocol
+       }
+       if normalizeReferenceProtocol(irequest.RequestType) == "tri" {
+               return "tri"
+       }
+       return "dubbo"
+}
+
+func directURLProtocol(rawURL string) (string, error) {
+       parsedURL, err := url.Parse(rawURL)
+       if err != nil {
+               return "", errors.Wrapf(err, "parse direct url %q", rawURL)
+       }
+       return normalizeReferenceProtocol(parsedURL.Scheme), nil
+}

Review Comment:
   `directURLProtocol` uses `url.Parse(rawURL)` and then reads 
`parsedURL.Scheme`. For direct addresses like `127.0.0.1:20880` (missing 
`://`), `url.Parse` treats `127.0.0.1` as the scheme, so this returns an 
invalid "protocol" and later builds a reference with 
`WithProtocol("127.0.0.1")`. Please detect missing schemes (e.g., no `://`) and 
fall back to a sensible default (like the declared request protocol / 
requestType, or "dubbo"), or validate the parsed scheme against known protocols 
and error clearly.



##########
tools/benchmark/go.mod:
##########
@@ -3,7 +3,7 @@ module github.com/apache/dubbo-go-pixiu/tools/benchmark
 go 1.25.0
 
 require (
-       dubbo.apache.org/dubbo-go/v3 v3.3.1
+       dubbo.apache.org/dubbo-go/v3 v3.0.0-20260210015753-35ea886421f9
        github.com/apache/dubbo-go-hessian2 v1.12.5

Review Comment:
   Same as the root module: this benchmark module is now pinned to 
`dubbo.apache.org/dubbo-go/v3 v3.0.0-20260210015753-35ea886421f9`, which 
conflicts with the PR description calling out v3.3.1. Please keep the benchmark 
module aligned with the intended dubbo-go version (or update the PR 
description/rationale accordingly).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to