shangxinxiaolin opened a new issue, #3756: URL: https://github.com/apache/dubbo-go/issues/3756
# [Bug]: Reference request timeout is overwritten by the consumer default ### What happened? An explicit reference-level `WithRequestTimeout(500 * time.Millisecond)` is overwritten by the consumer-level default `3s` when `ReferenceOptions.refer()` builds the reference URL. Expected: the constructed reference URL has `timeout=500ms`. Actual: it has `timeout=3s`. I reproduced the URL construction behavior with a mock protocol and cluster, invoking the actual `ReferenceOptions.Refer()` path. This reproduction does not make a network RPC or measure end-to-end call duration. Root cause: - [`getURLMap()`](https://github.com/apache/dubbo-go/blob/832124aaacf0283445d379e935ff5d73695fa84d/client/action.go#L415-L417) sets the reference timeout. - [`refer()`](https://github.com/apache/dubbo-go/blob/832124aaacf0283445d379e935ff5d73695fa84d/client/action.go#L129-L138) first applies `WithParams(refOpts.getURLMap())`, then unconditionally overwrites the timeout with `refOpts.Consumer.RequestTimeout`. - The Triple client [reads the resulting URL timeout](https://github.com/apache/dubbo-go/blob/832124aaacf0283445d379e935ff5d73695fa84d/protocol/triple/client.go#L132-L134) as its default call timeout. Possible fix: use the consumer-level timeout only as a fallback when the reference-level timeout is empty, preserving an explicitly configured reference timeout. ### How can we reproduce it? Add the following file as `client/timeout_issue_repro_test.go`: ```go package client import ( "testing" "time" "dubbo.apache.org/dubbo-go/v3/cluster/cluster" "dubbo.apache.org/dubbo-go/v3/cluster/directory" "dubbo.apache.org/dubbo-go/v3/common" "dubbo.apache.org/dubbo-go/v3/common/constant" "dubbo.apache.org/dubbo-go/v3/common/extension" "dubbo.apache.org/dubbo-go/v3/global" "dubbo.apache.org/dubbo-go/v3/protocol/base" ) type timeoutIssueProtocol struct{ captured *common.URL } func (p *timeoutIssueProtocol) Export(base.Invoker) base.Exporter { return nil } func (p *timeoutIssueProtocol) Destroy() {} func (p *timeoutIssueProtocol) Refer(u *common.URL) base.Invoker { p.captured = u return base.NewBaseInvoker(u) } type timeoutIssueCluster struct{} func (timeoutIssueCluster) Join(d directory.Directory) base.Invoker { return base.NewBaseInvoker(d.GetURL()) } func TestIssueReferenceTimeoutPrecedence(t *testing.T) { p := &timeoutIssueProtocol{} extension.SetProtocol("timeout-issue-repro", func() base.Protocol { return p }) extension.SetCluster("timeout-issue-repro", func() cluster.Cluster { return timeoutIssueCluster{} }) opts := defaultReferenceOptions() opts.Consumer = global.DefaultConsumerConfig() opts.Consumer.RequestTimeout = "3s" WithRequestTimeout(500 * time.Millisecond)(opts) opts.Reference.InterfaceName = "example.TimeoutService" opts.Reference.Protocol = "timeout-issue-repro" opts.Reference.Cluster = "timeout-issue-repro" opts.Reference.URL = "timeout-issue-repro://127.0.0.1:20000" opts.Reference.Filter = "-default" opts.Refer() if p.captured == nil { t.Fatal("Refer did not capture a URL") } actual := p.captured.GetParam(constant.TimeoutKey, "") t.Logf("consumer=%s reference=%s effective=%s", opts.Consumer.RequestTimeout, opts.Reference.RequestTimeout, actual) if actual != "500ms" { t.Fatalf("expected reference timeout 500ms, got %s", actual) } } ``` Run: ```sh go test ./client -run '^TestIssueReferenceTimeoutPrecedence$' -count=1 -v ``` Relevant output: ```text === RUN TestIssueReferenceTimeoutPrecedence timeout_issue_repro_test.go:51: consumer=3s reference=500ms effective=3s timeout_issue_repro_test.go:53: expected reference timeout 500ms, got 3s --- FAIL: TestIssueReferenceTimeoutPrecedence (0.01s) FAIL ``` ### Environment - Dubbo-Go: Apache `main`, commit `832124aaacf0283445d379e935ff5d73695fa84d` (the local fork HEAD matches the upstream main HEAD checked during investigation) - Go: `go1.25.5 windows/amd64` - OS: Windows - Consumer timeout: `3s` - Reference timeout: `500ms` - Reproduction uses mock transport and cluster extensions; no registry or external server is required. -- 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]
