Overview
reviewRunningMigrations (go/vt/vttablet/onlineddl/executor.go) treats vreplication state Error on a running vrepl Online DDL migration as terminal: it cancels the migration and marks it failed. But "state Error" conflates two very different situations:
- Genuinely unrecoverable errors —
isUnrecoverableError (FAILED_PRECONDITION vterrors, the known-fatal MySQL errnos: schema mismatch, bad data, etc.). Failing the migration is correct.
- Errors made terminal only by the
--vreplication-max-time-to-retry-on-error same-error window — a long network partition to the source, a source tablet unavailable for an extended stretch, a slow-but-alive applier stalling. The underlying stream is fully resumable: the _vt.vreplication row and _vt.copy_state checkpoints are intact, and a plain Workflow start resumes the copy from the stored lastpk.
The asymmetry is what makes the current behavior expensive: cancel is destructive (a later RETRY starts a fresh shadow table and re-copies everything, discarding potentially days of multi-shard row-copy work) while resume is nearly free. #20922 removed the throttling-induced instance of this (the vplayer stall detector firing during sustained throttling), but any other resumable-class error that repeats past the window still converts a healthy, resumable migration into failed.
Suggested approach
When the executor sees vreplication state Error on a running migration, classify before acting:
- Unrecoverable class → cancel/fail as today.
- Resumable class → keep the migration alive with an operator-visible "stuck: vreplication stream errored but is resumable" condition (probably remaining in
running with a liveness message, since there is no "stuck" migration status and inventing one has its own semantics — interaction with the stale-migration reaper needs care), and either leave resumption to the operator or auto-issue the equivalent of Workflow start on a slow, bounded backoff.
Design questions to settle:
- Auto-resume vs. operator bound. The stream reached terminal state precisely because the operator bounded retries with
--vreplication-max-time-to-retry-on-error; the executor auto-resuming overrides that judgment. It likely wants an opt-in (ddl_strategy flag) and/or a bounded resume budget, rather than unconditional auto-resume.
- Structured error classification. The executor currently learns the error from the message string. The robust fix is a structured error class carried with the vreplication row: today
errVPlayerStalled carries no vterrors code, and vterrors.Wrap does not support errors.Is chain traversal, so nothing can classify these errors except by string matching. A small cross-component contract (e.g. an error-class column or a coded message convention) would benefit non-DDL consumers of stream state too.
- This is a behavior change in failure handling and needs a release-note callout when implemented.
References
Overview
reviewRunningMigrations(go/vt/vttablet/onlineddl/executor.go) treats vreplication stateErroron a running vrepl Online DDL migration as terminal: it cancels the migration and marks itfailed. But "stateError" conflates two very different situations:isUnrecoverableError(FAILED_PRECONDITIONvterrors, the known-fatal MySQL errnos: schema mismatch, bad data, etc.). Failing the migration is correct.--vreplication-max-time-to-retry-on-errorsame-error window — a long network partition to the source, a source tablet unavailable for an extended stretch, a slow-but-alive applier stalling. The underlying stream is fully resumable: the_vt.vreplicationrow and_vt.copy_statecheckpoints are intact, and a plainWorkflow startresumes the copy from the stored lastpk.The asymmetry is what makes the current behavior expensive: cancel is destructive (a later
RETRYstarts a fresh shadow table and re-copies everything, discarding potentially days of multi-shard row-copy work) while resume is nearly free. #20922 removed the throttling-induced instance of this (the vplayer stall detector firing during sustained throttling), but any other resumable-class error that repeats past the window still converts a healthy, resumable migration intofailed.Suggested approach
When the executor sees vreplication state
Erroron a running migration, classify before acting:runningwith a liveness message, since there is no "stuck" migration status and inventing one has its own semantics — interaction with the stale-migration reaper needs care), and either leave resumption to the operator or auto-issue the equivalent ofWorkflow starton a slow, bounded backoff.Design questions to settle:
--vreplication-max-time-to-retry-on-error; the executor auto-resuming overrides that judgment. It likely wants an opt-in (ddl_strategyflag) and/or a bounded resume budget, rather than unconditional auto-resume.errVPlayerStalledcarries no vterrors code, andvterrors.Wrapdoes not supporterrors.Ischain traversal, so nothing can classify these errors except by string matching. A small cross-component contract (e.g. an error-class column or a coded message convention) would benefit non-DDL consumers of stream state too.References
failedwhileWorkflow startwould have resumed it).