Skip to content

fix(versioning): stop filing every operational failure under the migration race - #42709

Merged
rusackas merged 2 commits into
apache:masterfrom
mikebridge:fix-version-changes-capture-observability
Aug 3, 2026
Merged

fix(versioning): stop filing every operational failure under the migration race#42709
rusackas merged 2 commits into
apache:masterfrom
mikebridge:fix-version-changes-capture-observability

Conversation

@mikebridge

Copy link
Copy Markdown
Contributor

SUMMARY

The versioning capture path swallows OperationalError/ProgrammingError to survive the pre-migration window where the versioning tables don't exist yet. But those exception classes also cover deadlocks, lock timeouts, and dropped connections — and the class-based swallow filed all of them under "table missing": no log line, no capture-error metric, while the user's save reported success and its version history quietly didn't exist. That defeats the module's own documented posture that capture regressions should be "alertable rather than log-grep-only."

Three sites, three consequences:

  • changes/listener.py — the whole save's change records dropped silently
  • baseline/collection.pyshadow_row_count returns None, so the caller skips baseline capture for the flush
  • queries.py (read path) — every affected save renders an empty change list

This PR adds is_missing_table_error(), which verifies the specific condition — pgcode/sqlstate 42P01 on PostgreSQL, errno 1146 on MySQL, "no such table" on SQLite — instead of inferring it from the exception class. The genuine migration race stays exactly as quiet as before; everything else now logs and, on the persist path, increments the existing superset.versioning.capture.* counter. The predicate is deliberately narrow: an ambiguous error gets logged, not swallowed — over-reporting is recoverable, a silent capture drop is not.

Disclosure: this change was developed with AI assistance (Claude), on behalf of and reviewed by @mikebridge.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A — observability-only change; no user-facing behaviour.

TESTING INSTRUCTIONS

  • pytest tests/unit_tests/versioning/test_db_errors.py — 9 tests pinning the driver shapes per supported metadata DB (psycopg2 pgcode, psycopg3 sqlstate, MySQL errno, SQLite message), including the negative cases (deadlock, lock-wait timeout, locked database, connection drop).
  • pytest tests/unit_tests/versioning/test_listener.py — the new test_transient_persist_failure_is_logged_and_counted fails against the previous listener (no log, no metric); test_missing_table_stays_silent_during_persist passes before and after, pinning that the benign case's behaviour is unchanged.
  • Manual: point a dev instance at a metadata DB where the versioning migration hasn't run — saves still succeed with no error noise (the migration race stays silent).

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

…ation race

The capture path swallows OperationalError/ProgrammingError to survive the
pre-migration window where the versioning tables don't exist yet. But those
classes also cover deadlocks, lock timeouts, and dropped connections — and
the class-based swallow filed all of them under "table missing": no log
line, no capture-error metric, while the user's save reported success and
its version history quietly didn't exist. That defeats the module's own
posture that capture regressions are alertable rather than log-grep-only.

Three sites, three consequences:
- changes/listener.py: the whole save's change records dropped silently
- baseline/collection.py: shadow_row_count returns None, so the caller
  skips baseline capture for the flush
- queries.py (read path): every affected save renders an empty change list

Add is_missing_table_error(), which verifies the specific condition —
pgcode/sqlstate 42P01 on PostgreSQL, errno 1146 on MySQL, "no such table"
on SQLite — instead of inferring it from the exception class. The genuine
migration race stays exactly as quiet as before; everything else now logs
and, on the persist path, increments the existing capture-error counter.

The predicate is deliberately narrow: an ambiguous error gets logged, not
swallowed — over-reporting is recoverable, a silent capture drop is not.

The transient-failure test fails against the previous listener (no log,
no metric); the missing-table test passes both before and after, pinning
that the benign case's behaviour is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added the logging Creates a UI or API endpoint that could benefit from logging. label Aug 3, 2026
@bito-code-review

bito-code-review Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #c94b63

Actionable Suggestions - 0
Review Details
  • Files reviewed - 6 · Commit Range: cb7faf0..cb7faf0
    • superset/versioning/baseline/collection.py
    • superset/versioning/changes/listener.py
    • superset/versioning/db_errors.py
    • superset/versioning/queries.py
    • tests/unit_tests/versioning/test_db_errors.py
    • tests/unit_tests/versioning/test_listener.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 47.72727% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.42%. Comparing base (06628bb) to head (c959f6a).
⚠️ Report is 16 commits behind head on master.

Files with missing lines Patch % Lines
superset/versioning/db_errors.py 38.46% 8 Missing ⚠️
superset/versioning/changes/listener.py 37.50% 5 Missing ⚠️
superset/versioning/baseline/collection.py 33.33% 4 Missing ⚠️
superset/versioning/queries.py 42.85% 4 Missing ⚠️
superset/versioning/metrics.py 80.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42709      +/-   ##
==========================================
- Coverage   65.43%   65.42%   -0.01%     
==========================================
  Files        2810     2812       +2     
  Lines      159528   159555      +27     
  Branches    36410    36415       +5     
==========================================
+ Hits       104380   104392      +12     
- Misses      53102    53116      +14     
- Partials     2046     2047       +1     
Flag Coverage Δ
hive 38.07% <38.63%> (+<0.01%) ⬆️
mysql 57.77% <47.72%> (-0.01%) ⬇️
postgres 57.81% <47.72%> (-0.01%) ⬇️
presto 39.96% <38.63%> (+<0.01%) ⬆️
python 59.20% <47.72%> (-0.01%) ⬇️
sqlite 57.44% <47.72%> (-0.01%) ⬇️
unit 100.00% <ø> (ø)

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

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

… the swallow

Follow-ups from a clean-code + tidy-first review pass over this PR:

- The two except arms in _persist_buffered_records carried byte-identical
  log+metric bodies; collapsed into one arm with the missing-table early
  return, so the message and the metric can't drift apart.
- The baseline probe logged its losses but never counted them — a blind
  quadrant in the alerting surface this PR exists to create. The metric
  helper moves to superset/versioning/metrics.py, shared by the
  change-record listener and the baseline probe, which now emits
  shadow_count errors.
- The read path's branch normalized to the same polarity as its siblings,
  and its docstring now describes both return paths instead of only the
  missing-table one.
- The two non-listener classify-then-log branches gained their own tests
  (missing table silent / locked database logged+counted), so deleting a
  log line or metric at any of the three sites now fails a test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Aug 3, 2026
@netlify

netlify Bot commented Aug 3, 2026

Copy link
Copy Markdown

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit c959f6a
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a70b26f88857a00081c1c1d
😎 Deploy Preview https://deploy-preview-42709--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@rusackas rusackas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice, this closes a real gap. Swallowing the whole OperationalError/ProgrammingError class for the migration race meant a deadlock or dropped connection would silently look identical to "table not there yet" and the save's version history would just quietly vanish. is_missing_table_error() narrowing to the actual driver codes (with SQLite's message fallback) is the right fix, and the driver-shape tests covering pg/mysql/sqlite plus the negative cases (deadlock, lock timeout, connection drop) are exactly what I'd want to see backing this. LGTM!

@bito-code-review

bito-code-review Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #696655

Actionable Suggestions - 0
Review Details
  • Files reviewed - 7 · Commit Range: cb7faf0..c959f6a
    • superset/versioning/baseline/collection.py
    • superset/versioning/changes/listener.py
    • superset/versioning/metrics.py
    • superset/versioning/queries.py
    • tests/unit_tests/versioning/test_collection.py
    • tests/unit_tests/versioning/test_listener.py
    • tests/unit_tests/versioning/test_queries_change_records.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@rusackas
rusackas merged commit bf34c7f into apache:master Aug 3, 2026
76 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

logging Creates a UI or API endpoint that could benefit from logging. size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants