mysqlctl: prevent closeBackupFiles from cancelling context on successful file close, protecting in-flight S3/Ceph uploads - #20771
Conversation
There was a problem hiding this comment.
🟢 Ready to approve
The focused lifecycle fix preserves failure behavior and includes regression coverage.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Ensures the XtraBackup file-close watchdog stops immediately after uploads finish.
Changes:
- Extracts backup-file closing and watchdog cancellation into
closeBackupFiles. - Cancels the AddFile context after every close outcome.
- Adds regression coverage for prompt cancellation.
File summaries
| File | Description |
|---|---|
go/vt/mysqlctl/xtrabackupengine.go |
Stops the close watchdog when file uploads finish. |
go/vt/mysqlctl/xtrabackupengine_test.go |
Tests successful close and prompt cancellation. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Medium
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Review ChecklistHello reviewers! 👋 Please follow this checklist when reviewing this Pull Request. General
Tests
Documentation
New flags
If a workflow is added or modified:
Backward compatibility
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2cd5efd74
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
a2cd5ef to
64051fa
Compare
There was a problem hiding this comment.
🟡 Not ready to approve
A watchdog scheduling race can still cancel successfully closed uploads.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟡 Human review recommended
Context lifetime changes affect asynchronous uploads across multiple storage backends and warrant final human validation.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
736e316 to
965915d
Compare
|
I feel like this would be helpful to backport to the v24 branch as well. |
There was a problem hiding this comment.
🟡 Not ready to approve
Successful data uploads must be drained before cancellation ownership is lost and MANIFEST processing begins.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 965915d4cc
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
🟢 Ready to approve
The upload lifecycle fix is consistent across affected backends and covers both success and timeout paths.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #20771 +/- ##
===========================================
- Coverage 69.67% 55.04% -14.63%
===========================================
Files 1614 46 -1568
Lines 216793 7505 -209288
===========================================
- Hits 151044 4131 -146913
+ Misses 65749 3374 -62375
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ackupFilesCancelsOnRealTimeout Signed-off-by: Jeremy Doupe <jeremy@doupe.com>
There was a problem hiding this comment.
🟡 Human review recommended
Concurrent cancellation and upload lifecycle changes across cloud backends warrant final human review.
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟡 Human review recommended
Cloud-upload lifecycle and timeout concurrency changes warrant final human validation despite no confirmed blocking defect.
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
mattlord
left a comment
There was a problem hiding this comment.
In addition to removing the release summary notes, I think that there are a few minor things that we should address before merging:
-
Update
AddFile's doc inbackupstorage/interface.go. It still says the context "is valid for the duration of the writes, until the WriteCloser is closed" — this PR's whole premise is that async backends consume it untilWait()returns, and the engine now keeps it live exactly that long. Updating the sentence keeps the next engine author from reintroducing the bug the old wording invites. -
Drop the redundant
cancelAddFiles()on theaddStripeFileserror path.finalErris the named return, so the outer defer already runscancelAddFiles(); bh.Wait()for that return. Harmless, but it reads as if the defer doesn't cover it. -
In
go/vt/mysqlctl/xtrabackupengine_test.go:252, I think we should userequire.ErrorIsinstead ofassert.ErrorIs;testifylintis currently failing on that line. -
Worth a note (or follow-up test): the drain-before-MANIFEST ordering itself is unpinned. The unit tests cover
closeBackupFilesandmergeCancelnicely, but nothing provesbackupFilesdrains uploads and checksbh.Error()before the caller writes the MANIFEST. Understandable givenbackupFilesneeds an xtrabackup binary — a fake-handle test of the defer, or just a comment/PR note, would keep that contract from silently regressing. -
Optional nit: preserve the cancellation cause in
mergeCancel. Withcontext.WithCancelCause(parent)+cancel(context.Cause(other)), an upload aborted via the per-file context reports why instead of a barecontext.Canceled.
Thanks, @jdoupe ! ❤️
…dant cancelAddFiles call Signed-off-by: Jeremy Doupe <jdoupe@backblaze.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
There was a problem hiding this comment.
🟡 Human review recommended
The concurrency and cancellation changes span multiple cloud-storage backends and merit final human validation.
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
@mattlord - I believe I've addressed each of these (I'm pretty sure (3) was already done. 🤷 ). Thank you! |
mattlord
left a comment
There was a problem hiding this comment.
LGTM! Just one small test cleanup thing remains. In go/vt/mysqlctl/xtrabackupengine_test.go:252-259, the new pinned comment is incorrect: this test never invokes a BackupHandle, bh.Error(), backupFiles, or the MANIFEST path. It only proves that the close watchdog cancels the context and that the closer returns that error. The block immediately below then says that the ordering is unpinned, so the two comments contradict each other and seem likely to confuse future readers. I think we should remove both comments, leaving the require.ErrorIs assertion, and track the optional MANIFEST-ordering test separately if desired.
Thanks, @jdoupe ! ❤️
Signed-off-by: Jeremy Doupe <jdoupe@backblaze.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
There was a problem hiding this comment.
🔵 Human review recommended
The changes alter concurrency and cancellation semantics across multiple backup backends and warrant final human validation.
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Description
(description generated by Claude Code)
The Bug
The original backupFiles() function had an inline defer block that imposed a timeout on Close() calls
for backup files. That timeout watchdog was flawed in two ways:
addFilesCtx.Done() to know when to stop. But addFilesCtx is the same context used by a background upload
goroutine (started by bh.AddFile()) to upload data to S3/Ceph. If Close() returns before the background
upload drains, and the watchdog then calls cancel(), it aborts an otherwise-successful upload
mid-flight.
addFilesCtx.Done() to know when to stop the watchdog. But cancelAddFiles was deferred after the inline
defer — meaning if backupFiles succeeded, addFilesCtx would never be cancelled, so the watchdog would
hang forever (or until its own timer expired).
The Fix
A new closeBackupFiles() function was extracted with a corrected design:
closure never cancels the context.
simply stops the timer and returns, leaving the context alive for bh.Wait() / EndBackup() to drain the
background upload.
cancelAddFiles is now only called when there's an actual error — keeping the old "kill straggling
uploads on failure" behavior intact.
Tests
Two new tests guard both directions:
the context is never cancelled, even after the watchdog timeout expires.
timeout, the watchdog logs the error and cancels the context so the stuck upload aborts instead of
hanging forever.
Related Issue(s)
Maybe #16825 and #19853
Checklist
Deployment Notes
AI Disclosure
This PR was generated primarily with Claude Code / Sonnet 5. Then reviewed here (as seen below) with Copilot. It was also reviewed with Claude Code / (local model) Qwen3.6-35B-A3B.