Skip to content

external workload: wire GCV2 coordination#69521

Merged
ti-chi-bot[bot] merged 28 commits into
pingcap:masterfrom
AmoebaProtozoa:gcv2-external-workload
Jul 15, 2026
Merged

external workload: wire GCV2 coordination#69521
ti-chi-bot[bot] merged 28 commits into
pingcap:masterfrom
AmoebaProtozoa:gcv2-external-workload

Conversation

@AmoebaProtozoa

@AmoebaProtozoa AmoebaProtozoa commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: ref #67765

Problem Summary:

In Starter deployments, TiDB instances are ephemeral. After the serving TiDB instances for a keyspace have been gone for a while, obsolete data can still remain in storage until another TiDB instance runs keyspace-level GC again. If that data stays around for too long, it can incur unnecessary storage cost.

GCV2 worker is the compensation path for this case. It gives TiDB a hook to notify the external workload controller after keyspace-level GC progresses, so the controller can later bring up a TiDB instance to finish a final cleanup round after the user TiDB has exited. The goal is to clean up left-over data promptly without keeping a serving TiDB instance alive just for GC.

What changed and how does it work?

This PR wires the GCV2 path through the existing Starter-only external workload manager:

  • Creates the external workload manager after storage initialization and attaches it to the storage instance so startup, session, and GC paths can use the same manager.
  • Seeds the controller with an initial GCV2 task after bootstrap loads the effective persisted tidb_gc_life_time when the master role uses keyspace-level GC.
  • Reports completed keyspace-level GC rounds to the controller, and recycles finished GCV2 work after each round.
  • Reports global tidb_gc_life_time changes to the controller after TiDB persists the sysvar.
  • Lets a dedicated GCV2 worker abort outstanding GCV2 work during bootstrap upgrade handling instead of running normal TiDB upgrade work.

No external workload manager is created outside Starter deploy mode, and [external-workload] remains Starter-only config, so non-Starter deployments do not take this path. A dedicated GCV2 worker fails closed if the manager cannot be initialized.

Check List

Tests

  • Unit test

Release note

None

Summary by CodeRabbit

  • New Features

    • Added coordination between external workload management and keyspace-level garbage collection.
    • GCV2 workers now validate required PD support during startup.
    • GC lifetime changes are synchronized with external workload management.
    • GC workers automatically recycle and register GCV2 tasks after safe-point updates.
    • GCV2 workers safely terminate during upgrades when required.
  • Bug Fixes

    • Improved handling of missing metadata, initialization failures, and cleanup errors.
    • Effective GC lifetime values are now consistently applied.

@ti-chi-bot

ti-chi-bot Bot commented Jun 29, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue do-not-merge/needs-tests-checked do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note-none Denotes a PR that doesn't merit a release note. labels Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds store-bound GCV2 manager lifecycle handling, PD keyspace-level GC checks, upgrade-time worker aborts, post-GC task notifications, and effective TiDBGCLifetime synchronization.

Changes

GCV2 External Workload Manager Integration

Layer / File(s) Summary
Manager contracts and store binding
pkg/extworkload/*
GCV2 lifetime APIs now use time.Duration; managers can be bound to and retrieved from storage, and abort behavior is covered by tests.
Server startup and GCV2 bootstrap
cmd/tidb-server/*
Server startup validates PD keyspace-level GC support, binds managers to storage, initializes GCV2 with the effective lifetime, and clears bindings during shutdown.
Upgrade bootstrap abort path
pkg/session/*
Starter upgrades retrieve the bound manager and abort GCV2 workers before continuing or terminating the process.
Post-GC GCV2 notification
pkg/store/gcworker/*
GC safe point completion triggers role-specific GCV2 recycle and registration operations.
TiDBGCLifetime synchronization
pkg/executor/*
Global GC lifetime changes are propagated to enabled keyspace-level external workload managers.
Bazel wiring
cmd/tidb-server/BUILD.bazel, pkg/session/BUILD.bazel, pkg/executor/BUILD.bazel, pkg/store/gcworker/BUILD.bazel
Adds external workload and PD client dependencies and adjusts test shard counts.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GCWorker
  participant Storage
  participant ExternalWorkloadManager
  participant PDClient
  GCWorker->>Storage: retrieve bound manager
  GCWorker->>PDClient: check keyspace-level GC mode
  GCWorker->>ExternalWorkloadManager: RecycleGCV2(safePoint)
  GCWorker->>ExternalWorkloadManager: RegisterGCV2(safePoint, gcLifeTime)
Loading

Possibly related PRs

Suggested labels: ok-to-test

Suggested reviewers: yudongusa, yangkeao, yibin87, d3hunter

Poem

I’m a rabbit with a GC clock,
Hopping through each storage block.
GCV2 wakes, then tasks align,
Lifetime flows in measured time.
PD nods; upgrades tread with care—
Fresh manager bindings bloom everywhere.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% 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 is concise and accurately summarizes the main change: wiring GCV2 coordination for external workload.
Description check ✅ Passed The description follows the template well, includes the issue number, problem summary, changes, tests, and release note.
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.
✨ 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.

@ti-chi-bot ti-chi-bot Bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jun 29, 2026
@ti-chi-bot ti-chi-bot Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jun 29, 2026
@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jun 30, 2026
@ti-chi-bot ti-chi-bot Bot removed the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jun 30, 2026
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 13.68421% with 82 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.8022%. Comparing base (1174be2) to head (c9f91f8).
⚠️ Report is 51 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #69521        +/-   ##
================================================
- Coverage   76.3270%   73.8022%   -2.5249%     
================================================
  Files          2041       2056        +15     
  Lines        561007     594317     +33310     
================================================
+ Hits         428200     438619     +10419     
- Misses       131906     153902     +21996     
- Partials        901       1796       +895     
Flag Coverage Δ
integration 40.7694% <13.6842%> (+1.1413%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 60.4471% <ø> (ø)
parser ∅ <ø> (∅)
br 46.6787% <ø> (-16.0724%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread pkg/store/gcworker/gc_worker.go Outdated
Comment thread pkg/executor/set.go Outdated
Comment thread pkg/executor/set.go Outdated
@ti-chi-bot ti-chi-bot Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 2, 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)
pkg/executor/set_test.go (1)

48-83: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Good regression test for the clamped-value fix; consider also covering the skip path.

This test directly validates the fix for the previously flagged clamping issue. Consider adding a companion case (e.g., Role() != RoleMaster or non-keyspace-level GC Meta()) asserting UpdateGCLifeTime is not called, to guard the gating condition against regression.

🤖 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 `@pkg/executor/set_test.go` around lines 48 - 83, Add a companion regression
case around
setGCLifeTimeManager/TestSetGCLifeTimeNotifiesExternalWorkloadWithEffectiveValue
to cover the skip path: verify that UpdateGCLifeTime is not invoked when the
manager is not eligible, such as when Role() does not return config.RoleMaster
or when Meta() does not advertise
pd.KeyspaceConfigGCManagementTypeKeyspaceLevel. Reuse the existing
setGCLifeTimeManager helper or a variant of it to assert updateCnt stays zero
after the same SET GLOBAL flow, so the gating logic in the external workload
notification path is protected against regressions.
🤖 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 `@pkg/executor/set_test.go`:
- Around line 48-83: Add a companion regression case around
setGCLifeTimeManager/TestSetGCLifeTimeNotifiesExternalWorkloadWithEffectiveValue
to cover the skip path: verify that UpdateGCLifeTime is not invoked when the
manager is not eligible, such as when Role() does not return config.RoleMaster
or when Meta() does not advertise
pd.KeyspaceConfigGCManagementTypeKeyspaceLevel. Reuse the existing
setGCLifeTimeManager helper or a variant of it to assert updateCnt stays zero
after the same SET GLOBAL flow, so the gating logic in the external workload
notification path is protected against regressions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2021041a-3884-40d2-8e9c-d7166826d098

📥 Commits

Reviewing files that changed from the base of the PR and between ab0e556 and 848d589.

📒 Files selected for processing (4)
  • pkg/executor/BUILD.bazel
  • pkg/executor/set.go
  • pkg/executor/set_test.go
  • pkg/store/gcworker/gc_worker.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/store/gcworker/gc_worker.go

Comment thread cmd/tidb-server/main.go Outdated
@ti-chi-bot

ti-chi-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

@ChangRui-Ryan: adding LGTM is restricted to approvers and reviewers in OWNERS files.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot

ti-chi-bot Bot commented Jul 8, 2026

Copy link
Copy Markdown

@wfxr: adding LGTM is restricted to approvers and reviewers in OWNERS files.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@D3Hunter D3Hunter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Summary

  • Total findings: 13
  • Inline comments: 13
  • Summary-only findings (no inline anchor): 0
Findings (highest risk first)

⚠️ [Major] (9)

  1. Abort helper hides unconditional process termination below the bootstrap layer (pkg/extworkload/util.go:68 (called from pkg/session/session.go:4601 and pkg/session/upgrade_run.go:48))
  2. Auto-analyze workers can complete GC without advancing controller state (pkg/store/gcworker/gc_worker.go:853)
  3. Global GC lifetime changes are dropped on non-master TiDB roles (pkg/executor/set.go:197)
  4. GCV2 initialization can be reordered behind the first GC notification (cmd/tidb-server/main.go:694 (cross-function handoff through pkg/session/session.go:4548 and pkg/store/gcworker/gc_worker.go:128,215,454,847))
  5. Mixed-version and rollback behavior is not gated or proven (cmd/tidb-server/main.go:682; pkg/store/gcworker/gc_worker.go:842; pkg/executor/set.go:195)
  6. Recycle-then-register can drop the replacement GCV2 task (pkg/store/gcworker/gc_worker.go:854)
  7. A temporary PAUSED controller response becomes a fatal worker restart loop (cmd/tidb-server/main.go:348)
  8. Upgrade abort runs before the synchronized bootstrap-version recheck (pkg/session/session.go:4601)
  9. The GCV2 lifetime API does not encode its seconds unit (pkg/extworkload/external_workload.go:37; pkg/extworkload/manager.go:137)

🟡 [Minor] (4)

  1. Best-effort controller calls can add 30-60 seconds to synchronous paths (pkg/executor/set.go:213; pkg/store/gcworker/gc_worker.go:854-873)
  2. Best-effort GCV2 failures are not exposed as outcome metrics (pkg/store/gcworker/gc_worker.go:855; pkg/executor/set.go:213; pkg/extworkload/manager.go:112-125,137-169)
  3. Effective GC lifetime can be read from a stale sysvar cache (pkg/executor/set.go:198)
  4. External-workload synchronization is embedded in the generic SET path (pkg/executor/set.go:195)

Comment thread pkg/extworkload/util.go Outdated
return
}

role := mgr.Role()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [Major] Auto-analyze workers can complete GC without advancing controller state

Why
RoleAutoAnalyzeWorker is a valid external-workload role, and these TiDB instances still start the normal GC worker and participate in its leader election. However, both notification branches omit that role, so a successful GC on an auto-analyze instance broadcasts the new safe point to PD but emits neither the recycle nor registration transition to the external controller.

Scope
pkg/store/gcworker/gc_worker.go:853

Risk if unchanged
If an auto-analyze instance becomes and remains GC leader, completed tasks at or below the new safe point are not recycled and no next GCV2 round is registered. The controller can retain obsolete work, lose the heartbeat used to schedule later rounds, and diverge from the keyspace's actual GC state.

Evidence
ExternalWorkload.Valid accepts RoleAutoAnalyzeWorker; BootstrapSession starts StartGCWorker without a role check; and GCWorker.tick/leaderTick contain no external-role filter. Yet notifyGCV2AfterGC recycles only master, TTL, and GCV2 roles and registers only master and TTL roles. The new test constructs only RoleGCV2Worker, so it also omits the master, TTL, and auto-analyze routing branches.

Change request
Please include auto-analyze workers in the appropriate recycle/register actions, as for TTL workers, or explicitly prevent that role from running or winning the GC worker. Add a role-matrix test for every valid ExternalWorkloadRole, asserting master and TTL recycle/register behavior, dedicated-worker recycle-only behavior, the lifetime passed to registration, and relevant failure paths.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for checking this path. Auto-analyze workers are already started with skip-gc-worker = true, so that role does not run or win the GC worker and cannot reach this post-GC notification. I therefore kept auto-analyze out of the recycle/register role matrix rather than duplicating the existing worker-startup restriction.

Comment thread pkg/executor/set.go Outdated
Comment thread cmd/tidb-server/main.go
if err != nil {
return nil, nil, err
}
initializeExternalWorkloadGCV2(context.Background(), storage, externalWorkloadManager)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [Major] GCV2 initialization can be reordered behind the first GC notification

Why
The manager is published on the store before BootstrapSession, but InitializeGCV2 is deferred until after BootstrapSession returns. Bootstrap starts the GC worker, whose first Starter-mode tick can launch a GC job immediately, so a completed GC can recycle and register safe point S before startup later seeds the controller with safe point 0.

Scope
cmd/tidb-server/main.go:694 (cross-function handoff through pkg/session/session.go:4548 and pkg/store/gcworker/gc_worker.go:128,215,454,847)

Risk if unchanged
The controller can observe a non-monotonic S -> 0 transition. Depending on replacement and queue semantics, that can recreate stale work, overwrite current task state, retain obsolete work, or schedule the next round from a stale heartbeat after restart.

Evidence
initExternalWorkloadManager binds the manager before BootstrapSession(storage). During bootstrap, raw.StartGCWorker() starts a first production Starter tick that does not apply gcWaitTime until one job has completed. If that job finishes first, notifyGCV2AfterGC sends safe point S, after which initializeExternalWorkloadGCV2 unconditionally calls RegisterGCV2(ctx, 0, gcLifeTime). The protocol describes this as the safe point of the most recent keyspace-level GC.

Change request
Please establish a monotonic initialization barrier before the GC worker can observe the manager, or seed from current controller/GC state under an ordering mechanism that prevents a later zero registration. Add a focused startup-ordering test in which the first GC notification completes before initialization and assert that the controller never observes S followed by 0.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for raising the ordering concern. I traced the current controller and worker behavior before deciding not to add a TiDB-local barrier. The zero value is a startup heartbeat, not an update of the PD GC safe point; controller registrations are stored as task rows and scheduling uses the latest heartbeat, while an activated worker computes GC state from TiDB/PD. The GC path also waits for the GC state-cache synchronization interval before performing GC operations. A local barrier would not provide a cross-node monotonic protocol, so startup ordering remains unchanged.

Comment thread cmd/tidb-server/main.go
}
}
}
externalWorkloadManager := initExternalWorkloadManager(context.Background(), storage)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [Major] Mixed-version and rollback behavior is not gated or proven

Why
This change starts creating and mutating controller-side GCV2 task state whenever the existing external-workload config is enabled, but there is no TiDB/controller capability gate or rollout epoch. An N-1 TiDB lacks the new initialization, post-GC recycle/register, lifetime-update, and upgrade-abort paths, while controller task state can outlive a rollback.

Scope
cmd/tidb-server/main.go:682; pkg/store/gcworker/gc_worker.go:842; pkg/executor/set.go:195

Risk if unchanged
During a rolling upgrade, controller progress can pause when GC leadership moves to an older node. After downgrade, outstanding tasks created by the newer binary can remain unadvanced or repeatedly schedule workers that the older binary never recycles, without an actionable incompatibility error or cleanup step.

Evidence
The change attaches the manager before bootstrap and activates GCV2 RPCs for eligible roles without adding min-version or capability negotiation, a persisted rollout gate, downgrade cleanup, a mixed-version test, or an N-to-N-1 rollback test. The new tests use one in-process binary and mocked managers.

Change request
Please define and prove the N/N-1 compatibility contract. Add an explicit capability/version gate or implement rollback cleanup, then add a mixed-version test that transfers GC leadership across N and N-1 nodes plus a downgrade test with pre-existing controller tasks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. This integration is opt-in through the existing Starter external-workload configuration. The rollout contract is to keep it disabled during a mixed-version TiDB rollout, enable it only after the supporting fleet is in place, and disable/drain it before rollback. Under that contract an N-1 node never participates in the controller protocol while the feature is active, so I did not add a second binary capability gate in this PR.

Comment thread pkg/extworkload/external_workload.go
Comment thread pkg/executor/set.go Outdated
logutil.BgLogger().Warn("failed to update external workload GC life time",
zap.String("name", name),
zap.String("val", gcLifeTimeVal),
zap.Error(err))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [Minor] Best-effort controller calls can add 30-60 seconds to synchronous paths

Why
Controller errors are treated as recoverable and log-only, yet the calls remain inline with a 30-second per-RPC timeout. A degraded controller can block SET GLOBAL tidb_gc_life_time for 30 seconds and keep a completed GC job marked running for up to 60 seconds across sequential recycle/register calls.

Scope
pkg/executor/set.go:213; pkg/store/gcworker/gc_worker.go:854-873

Risk if unchanged
Controller latency directly inflates administrative SQL tail latency and delays GC worker completion and cooldown accounting even though neither path requires the RPC to succeed for local success.

Evidence
requestTimeout is 30 seconds. SetExecutor calls UpdateGCLifeTime synchronously after persisting the variable, while notifyGCV2AfterGC serially invokes recycle and register before runGCJob returns and clears gcIsRunning through the done channel.

Change request
Please move best-effort coordination off the SQL and GC completion paths into a bounded single-owner reconciler with explicit backpressure, or apply a much smaller dependency budget. Preserve update ordering and coalesce superseded lifetime values rather than spawning unbounded work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the latency concern. I kept the calls synchronous and bounded in this PR because they preserve ordering with the persisted SET and the completed GC transition. Moving them off-path safely needs a single-owner reconciler with persistence, coalescing, and backpressure; simply spawning asynchronous work could reorder or lose updates. The existing 30-second per-RPC bound and warning logs remain, and a reconciler can be handled as a separate design change.


role := mgr.Role()
if role == config.RoleMaster || role == config.RoleTTLTaskWorker || role == config.RoleGCV2Worker {
if err := mgr.RecycleGCV2(ctx, safePoint); err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 [Minor] Best-effort GCV2 failures are not exposed as outcome metrics

Why
The changed paths deliberately swallow controller failures, so operators need an alertable success/failure signal. The existing metric interceptor increments only an attempt counter before invocation, and UpdateGCLifeTime does not attach metric labels at all.

Scope
pkg/store/gcworker/gc_worker.go:855; pkg/executor/set.go:213; pkg/extworkload/manager.go:112-125,137-169

Risk if unchanged
A controller outage or sustained PAUSED/error response can silently disable coordination except for sampled log inspection; dashboards cannot distinguish healthy task traffic from repeated failures or measure timeout saturation.

Evidence
ExternalWorkloadTaskCounter has only worker-type and action labels and is incremented before the invocation returns. No result or latency metric is recorded, while the new callers convert errors into warnings and continue.

Change request
Please add bounded-cardinality outcome and latency metrics for these RPCs, including UpdateGCLifeTime, so alerts can distinguish success, timeout/cancellation, PAUSED, and other failures without using keyspace identifiers as labels.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. The existing counter records attempts and failures remain visible through structured warning logs, but I agree that result and latency metrics would improve alerting. I did not add a GCV2-only metric shape here because outcome classification should be consistent across all external-workload RPCs, including PAUSED, timeout, cancellation, and other errors. That is better handled as a focused metrics follow-up.

Comment thread pkg/executor/set.go Outdated
Comment thread pkg/executor/set.go
Comment thread cmd/tidb-server/main.go Outdated
Comment thread cmd/tidb-server/main.go
Comment on lines +367 to +384
func loadExternalWorkloadGCLifeTime(ctx context.Context, storage kv.Storage) (time.Duration, error) {
se, err := session.CreateSession(storage)
if err != nil {
return 0, err
}
defer se.Close()
gcLifeTimeVal, err := variable.GetSysVar(vardef.TiDBGCLifetime).GetGlobalFromHook(ctx, se.GetSessionVars())
if err != nil {
return 0, err
}
gcLifeTime, err := time.ParseDuration(gcLifeTimeVal)
if err != nil {
return 0, err
}
return gcLifeTime, nil
}

func initializeExternalWorkloadGCV2(ctx context.Context, storage kv.Storage, mgr extworkload.Manager) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe move those logic away into extworkload pkg

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. I kept this startup orchestration in cmd/tidb-server because loading the effective global sysvar requires creating a session; moving that into extworkload would introduce a reverse dependency from the coordination package back to session startup. The manager operation and duration conversion remain owned by extworkload.

Comment thread pkg/executor/set.go Outdated
Comment thread pkg/extworkload/manager.go Outdated
Comment thread pkg/extworkload/external_workload.go Outdated
Comment thread pkg/session/session.go Outdated
Comment thread pkg/session/upgrade_run.go Outdated
return nil
}

func (w *GCWorker) notifyGCV2AfterGC(ctx context.Context, safePoint uint64) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

except w.loadDurationWithDefault, most code are extworkload related, maybe make a function in extworkload and pass param to it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion. I kept this orchestration in gcworker because it depends on the private GC lifetime loader and must run at the exact point after a successful local safe-point broadcast. Moving it would either expose GC-worker internals or split the role transition across packages. The extworkload manager continues to own RPC execution, timeouts, and protocol conversion.

@AmoebaProtozoa AmoebaProtozoa requested a review from D3Hunter July 14, 2026 09:33
@ti-chi-bot ti-chi-bot Bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jul 14, 2026

@D3Hunter D3Hunter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

rest lgtm

Comment thread pkg/extworkload/manager.go Outdated
Comment thread pkg/extworkload/manager.go Outdated
Comment thread pkg/extworkload/manager.go Outdated
Comment thread pkg/session/session.go Outdated
@ti-chi-bot

ti-chi-bot Bot commented Jul 14, 2026

Copy link
Copy Markdown

@AmoebaProtozoa: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
pull-error-log-review c9f91f8 link false /test pull-error-log-review

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@ti-chi-bot

ti-chi-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ChangRui-Ryan, D3Hunter, wfxr, wjhuang2016

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

The pull request process is described here

Details Needs approval from an approver in each of these files:
  • OWNERS [D3Hunter,wjhuang2016]

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

@ti-chi-bot ti-chi-bot Bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jul 15, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 15, 2026

Copy link
Copy Markdown

[LGTM Timeline notifier]

Timeline:

  • 2026-07-14 12:01:36.212272685 +0000 UTC m=+715082.248367742: ☑️ agreed by wjhuang2016.
  • 2026-07-15 02:05:04.597452372 +0000 UTC m=+765690.633547428: ☑️ agreed by D3Hunter.

@ti-chi-bot ti-chi-bot Bot merged commit 1750c20 into pingcap:master Jul 15, 2026
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm release-note-none Denotes a PR that doesn't merit a release note. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants