Skip to content

locate: fail fast on TLS authentication errors instead of backoffer retry#1972

Open
xhebox wants to merge 1 commit into
tikv:masterfrom
xhebox:tls-fail-fast
Open

locate: fail fast on TLS authentication errors instead of backoffer retry#1972
xhebox wants to merge 1 commit into
tikv:masterfrom
xhebox:tls-fail-fast

Conversation

@xhebox

@xhebox xhebox commented May 20, 2026

Copy link
Copy Markdown

What is changed and how it works?

When a TiDB cluster table (e.g. CLUSTER_TIDB_TRX) fans out to a peer TiDB node whose advertise-address is empty, the status address becomes :10080. gRPC normalizes this to localhost:10080, causing TLS ServerName = "localhost" which fails certificate verification.

Previously, this TLS error was treated as a transient RPC failure and retried by the backoffer until the 40000ms budget was exhausted, turning an instant configuration bug into a ~40s query hang.

This PR detects TLS authentication errors in onSendFail and returns them immediately without retry, since certificate mismatches are permanent configuration issues that will not recover by waiting.

ref pingcap/tidb#68519

Changes

  • internal/locate/region_request.go: add isTLSAuthError() helper and use it in onSendFail() to bypass backoffer retry for TLS errors.
  • internal/locate/region_request_test.go: add TestSendReqTLSFailFast to verify zero retries for x509 errors.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No code

Side effects

  • Breaking backward compatibility
  • Performance regression

Related changes

  • Need to cherry-pick to the release branch
  • Need to update the documentation (none)
  • Need to update the tidb-ansible repository (none)

Release note

  • Fail fast on TLS authentication errors instead of retrying until backoffer timeout.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • TLS authentication certificate handshake failures are now treated as permanent, non-retriable errors. This prevents unnecessary retry attempts and improves response time for authentication failures.
  • Tests

    • Added test coverage to verify that TLS authentication failures fail fast without retries.

Review Change Stack

…etry

When a TiDB cluster table (e.g. CLUSTER_TIDB_TRX) fans out to a peer TiDB
node whose advertise-address is empty, the status address becomes :10080.
gRPC normalizes this to localhost:10080, causing TLS ServerName = "localhost"
which fails certificate verification.

Previously, this TLS error was treated as a transient RPC failure and retried
by the backoffer until the 40000ms budget was exhausted, turning an instant
configuration bug into a ~40s query hang.

This commit detects TLS authentication errors in onSendFail and returns them
immediately without retry, since certificate mismatches are permanent
configuration issues that will not recover by waiting.

Signed-off-by: xhe <xw897002528@gmail.com>
@ti-chi-bot ti-chi-bot Bot added the dco-signoff: yes Indicates the PR's author has signed the dco. label May 20, 2026
@ti-chi-bot

ti-chi-bot Bot commented May 20, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign niedhui for approval. For more information see the Code Review Process.
Please ensure that each of them provides their approval before proceeding.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Region request sending now detects TLS/authentication certificate handshake failures and treats them as non-retriable permanent errors, short-circuiting the retry/backoff logic. A new helper function identifies such failures, onSendFail uses it to return immediately, and tests verify zero-retry behavior for both sync and async paths.

Changes

TLS Authentication Fast-Fail

Layer / File(s) Summary
TLS error detection and fast-fail implementation
internal/locate/region_request.go
Introduces isTLSAuthError() helper to detect TLS/authentication certificate failures by checking for x509: or authentication handshake failed substrings, and modifies onSendFail to short-circuit immediately when such errors are encountered, skipping retry/backoff logic.
Test coverage for TLS fast-fail
internal/locate/region_request_test.go
Adds gRPC error simulation imports and TestSendReqTLSFailFast which verifies that TLS handshake failures (x509 errors) result in zero retries and immediate error return, tested in both sync and async API modes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A certificate error won't retry today,
Fast-fail now whisks TLS troubles away,
No backoff, no waiting for handshakes to mend,
Just quick-exit logic right where errors end! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: treating TLS authentication errors as permanent failures instead of retrying via backoffer, which is the core purpose of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ti-chi-bot ti-chi-bot Bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label May 20, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/locate/region_request_test.go (1)

1285-1291: ⚡ Quick win

Async retry assertion is currently non-verifying.

retryTimes isn’t a reliable signal in AsyncAPI mode here: SendReqCtx returns 0 unconditionally on the failpoint async path (Line 1493 in internal/locate/region_request.go). Please assert actual send attempts (client fn call count) to prove fail-fast/no-retry behavior.

Proposed test hardening
 	test := func() {
 		oc := s.regionRequestSender.client
 		defer func() {
 			s.regionRequestSender.client = oc
 		}()
+		attempts := 0

 		// Simulate the gRPC error produced when TLS ServerName "localhost" does not match cert SANs.
 		tlsErr := status.Error(codes.Unavailable,
 			`connection error: desc = "transport: authentication handshake failed: `+
 				`tls: failed to verify certificate: x509: certificate is valid for example.com, not localhost"`)

 		s.regionRequestSender.client = &fnClient{fn: func(ctx context.Context, addr string, req *tikvrpc.Request, timeout time.Duration) (*tikvrpc.Response, error) {
+			attempts++
 			return nil, tlsErr
 		}}

 		bo := retry.NewBackofferWithVars(context.Background(), 5, nil)
 		resp, retryTimes, err := s.regionRequestSender.SendReq(bo, req, region.Region, time.Second)
 		s.Nil(resp)
 		s.NotNil(err)
 		// TLS auth error should fail fast without any retry.
 		s.Zero(retryTimes)
+		s.Equal(1, attempts)
 		s.Contains(err.Error(), "x509:")
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/locate/region_request_test.go` around lines 1285 - 1291, The test
currently relies on retryTimes (returned by SendReq) which is non-verifying in
the async failpoint path; instead modify the test to assert the actual number of
send attempts by inspecting the mock client function call count used by
regionRequestSender (e.g. the mock send/ClientFn you registered) after calling
SendReq/SendReqCtx, verify it is exactly 1 (or 0 depending on expected
fail-fast) to prove no retries, keep the existing assertions for resp nil and
error containing "x509:", and remove or de-emphasize reliance on retryTimes
returned by SendReq/SendReqCtx.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/locate/region_request_test.go`:
- Around line 1285-1291: The test currently relies on retryTimes (returned by
SendReq) which is non-verifying in the async failpoint path; instead modify the
test to assert the actual number of send attempts by inspecting the mock client
function call count used by regionRequestSender (e.g. the mock send/ClientFn you
registered) after calling SendReq/SendReqCtx, verify it is exactly 1 (or 0
depending on expected fail-fast) to prove no retries, keep the existing
assertions for resp nil and error containing "x509:", and remove or de-emphasize
reliance on retryTimes returned by SendReq/SendReqCtx.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 05351ff1-e215-4037-832a-5200b4e138d4

📥 Commits

Reviewing files that changed from the base of the PR and between fb7ee09 and 7960405.

📒 Files selected for processing (2)
  • internal/locate/region_request.go
  • internal/locate/region_request_test.go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the dco. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant