Skip to content

fix(reports): make #42253 screenshot readiness production-safe - #42427

Merged
aminghadersohi merged 3 commits into
apache:fix-non-tiled-vacuous-passfrom
fitzee:fix-non-tiled-vacuous-pass-prod-safe
Jul 26, 2026
Merged

fix(reports): make #42253 screenshot readiness production-safe#42427
aminghadersohi merged 3 commits into
apache:fix-non-tiled-vacuous-passfrom
fitzee:fix-non-tiled-vacuous-pass-prod-safe

Conversation

@fitzee

@fitzee fitzee commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

Reviewed production-safety follow-up for #42253.

This replaces readiness and diagnostic selectors that rely on data-test attributes with the existing production classes (.dashboard-component-chart-holder.dashboard-chart-id-* and .slice_container). Production builds, including Docker builds under the production BABEL_ENV, run babel-plugin-jsx-remove-data-test-id, so the prior selectors became no-ops in the deployment mode that matters. The selector is shared across polling and diagnostics, and chart IDs are extracted from the unconditional dashboard-chart-id-<digits> class.

The shared selector change also changes tiled semantics: it excludes Markdown and Dynamic components that share the holder test hook but are not charts. This fixes the latent #42119 Markdown/Dynamic nothing_mounted deadlock. Because #42119 has already merged with a selector that is a production no-op, that merged path still needs a follow-up using this production-safe selector.

For non-tiled captures, dashboard/standalone captures use the holder predicate while chart-container captures use a positive chart predicate requiring a terminal marker and no .loading. Standalone dashboard captures warn when zero chart holders make the readiness gate inactive. The runtime guard derives an effective screenshot budget from Celery task hard/soft limits, reserving cleanup/error-transition time; this may duplicate or overlap the still-open #42118 and should be reconciled when that work lands.

This hardens and fixes #42253. It does not establish the root cause of the pre-existing PointFive SC-113788 incident.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Not applicable; backend screenshot readiness and diagnostics only. The four frontend changes from the earlier patch are reverted because existing production classes are the contract.

TESTING INSTRUCTIONS

  • python3 -m pytest -q tests/unit_tests/utils/test_screenshot_utils.py tests/unit_tests/utils/webdriver_test.py (requires the complete Superset Python test environment)
  • ruff check superset/utils/screenshot_utils.py superset/utils/webdriver.py tests/unit_tests/utils/test_screenshot_utils.py tests/unit_tests/utils/webdriver_test.py
  • ruff format --check superset/utils/screenshot_utils.py superset/utils/webdriver.py tests/unit_tests/utils/test_screenshot_utils.py tests/unit_tests/utils/webdriver_test.py
  • pre-commit run --all-files (mypy main and extension checks passed; local all-files run otherwise encountered environment/upstream blockers documented in the companion report)
  • git diff --check

ADDITIONAL INFORMATION

@bito-code-review

bito-code-review Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped - Branch Excluded

Bito didn't auto-review because the source or target branch is excluded from automatic reviews.
No action is needed if you didn't intend for the agent to review it. Otherwise, to manually trigger a review, type /review in a comment and save.
You can change the branch exclusion settings here, or contact your Bito workspace admin at evan@preset.io.

@fitzee
fitzee marked this pull request as ready for review July 26, 2026 00:29
@dosubot dosubot Bot added alert-reports Namespace | Anything related to the Alert & Reports feature change:frontend Requires changing the frontend dashboard Namespace | Anything related to the Dashboard labels Jul 26, 2026
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.70588% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.23%. Comparing base (62408be) to head (839ea71).

Files with missing lines Patch % Lines
superset/utils/webdriver.py 0.00% 5 Missing ⚠️
superset/utils/screenshot_utils.py 91.66% 1 Missing ⚠️
Additional details and impacted files
@@                     Coverage Diff                     @@
##           fix-non-tiled-vacuous-pass   #42427   +/-   ##
===========================================================
  Coverage                       65.22%   65.23%           
===========================================================
  Files                            2795     2795           
  Lines                          157682   157694   +12     
  Branches                        36066    36067    +1     
===========================================================
+ Hits                           102853   102865   +12     
- Misses                          52852    52853    +1     
+ Partials                         1977     1976    -1     
Flag Coverage Δ
hive 38.39% <64.70%> (+<0.01%) ⬆️
javascript 71.26% <ø> (ø)
mysql 57.56% <64.70%> (+<0.01%) ⬆️
postgres 57.60% <64.70%> (+<0.01%) ⬆️
presto 40.31% <64.70%> (+<0.01%) ⬆️
python 59.01% <64.70%> (+<0.01%) ⬆️
sqlite 57.23% <64.70%> (+<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.

@aminghadersohi
aminghadersohi merged commit ddd9ad0 into apache:fix-non-tiled-vacuous-pass Jul 26, 2026
57 checks passed
eschutho added a commit that referenced this pull request Jul 31, 2026
… hitting Celery kill

Cumulative per-tile readiness waits in take_tiled_screenshot() have no
bound tied to the running Celery task's time limit: each tile's
wait_for_function runs at the full configured load_wait, so a slow
dashboard with N tiles can wait up to N * load_wait and get SIGKILLed
mid-capture (SoftTimeLimitExceeded) instead of the report failing
cleanly and notifying owners.

Reworked from this PR's original revision to sit on top of the merged
#42253/#42427 readiness work and reuse its runtime budget helper rather
than shipping a second one:

- Derive one wall-clock budget for the whole tiled operation from
  resolve_screenshot_task_budget_seconds() (the #42427 helper the
  non-tiled path already uses). When it returns None (no Celery task
  context, e.g. synchronous thumbnail generation), fall back to a fixed
  total ceiling (TILED_SCREENSHOT_TOTAL_WAIT_BUDGET_SECONDS = 1440s)
  instead of "keep the configured timeout" -- unlike the non-tiled
  path's single wait, per-tile waits accumulate, so the operation still
  needs one bounded total.
- Cap each tile's readiness-wait timeout at the remaining budget,
  recomputed after the mandatory scroll-settle sleep (which itself
  consumes wall-clock time) so a tile can't overrun by up to one settle
  interval. Cap or skip the cosmetic per-tile animation wait the same
  way.
- Raise TiledScreenshotBudgetExceededError the moment the budget is
  exhausted -- before any further tile is captured -- and exempt it from
  the function's return-None fallback so callers fail the report loudly
  instead of receiving a partial/unchecked screenshot. No budget floor:
  a budget already exhausted by setup raises before the first tile,
  matching the non-tiled path's raise-before-capture semantics.
- Make the new error a subclass of ScreenshotTaskBudgetExceededError
  (moved to screenshot_utils.py, re-exported from webdriver.py) so
  callers can catch the whole budget-error family with one type.
- Enrich the per-tile timeout WARNING with budget context (waited vs
  requested load_wait, elapsed vs total budget, tiles captured) and add
  a per-tile DEBUG timing breakdown so slow dashboards can be profiled
  from logs alone.

Co-Authored-By: Claude <noreply@anthropic.com>
eschutho added a commit that referenced this pull request Jul 31, 2026
… hitting Celery kill

Cumulative per-tile readiness waits in take_tiled_screenshot() have no
bound tied to the running Celery task's time limit: each tile's
wait_for_function runs at the full configured load_wait, so a slow
dashboard with N tiles can wait up to N * load_wait and get SIGKILLed
mid-capture (SoftTimeLimitExceeded) instead of the report failing
cleanly and notifying owners.

Reworked from this PR's original revision to sit on top of the merged
#42253/#42427 readiness work and reuse its runtime budget helper rather
than shipping a second one:

- Derive one wall-clock budget for the whole tiled operation from
  resolve_screenshot_task_budget_seconds() (the #42427 helper the
  non-tiled path already uses). When it returns None (no Celery task
  context, e.g. synchronous thumbnail generation), fall back to a fixed
  total ceiling (TILED_SCREENSHOT_TOTAL_WAIT_BUDGET_SECONDS = 1440s)
  instead of "keep the configured timeout" -- unlike the non-tiled
  path's single wait, per-tile waits accumulate, so the operation still
  needs one bounded total.
- Cap each tile's readiness-wait timeout at the remaining budget,
  recomputed after the mandatory scroll-settle sleep (which itself
  consumes wall-clock time) so a tile can't overrun by up to one settle
  interval. Cap or skip the cosmetic per-tile animation wait the same
  way.
- Raise TiledScreenshotBudgetExceededError the moment the budget is
  exhausted -- before any further tile is captured -- and exempt it from
  the function's return-None fallback so callers fail the report loudly
  instead of receiving a partial/unchecked screenshot. No budget floor:
  a budget already exhausted by setup raises before the first tile,
  matching the non-tiled path's raise-before-capture semantics.
- Make the new error a subclass of ScreenshotTaskBudgetExceededError
  (moved to screenshot_utils.py, re-exported from webdriver.py) so
  callers can catch the whole budget-error family with one type.
- Enrich the per-tile timeout WARNING with budget context (waited vs
  requested load_wait, elapsed vs total budget, tiles captured) and add
  a per-tile DEBUG timing breakdown so slow dashboards can be profiled
  from logs alone.

Co-Authored-By: Claude <noreply@anthropic.com>
eschutho added a commit that referenced this pull request Jul 31, 2026
… hitting Celery kill

Cumulative per-tile readiness waits in take_tiled_screenshot() have no
bound tied to the running Celery task's time limit: each tile's
wait_for_function runs at the full configured load_wait, so a slow
dashboard with N tiles can wait up to N * load_wait and get SIGKILLed
mid-capture (SoftTimeLimitExceeded) instead of the report failing
cleanly and notifying owners.

Reworked from this PR's original revision to sit on top of the merged
#42253/#42427 readiness work and reuse its runtime budget helper rather
than shipping a second one:

- Derive one wall-clock budget for the whole tiled operation from
  resolve_screenshot_task_budget_seconds() (the #42427 helper the
  non-tiled path already uses). When it returns None (no Celery task
  context, e.g. synchronous thumbnail generation), fall back to a fixed
  total ceiling (TILED_SCREENSHOT_TOTAL_WAIT_BUDGET_SECONDS = 1440s)
  instead of "keep the configured timeout" -- unlike the non-tiled
  path's single wait, per-tile waits accumulate, so the operation still
  needs one bounded total.
- Cap each tile's readiness-wait timeout at the remaining budget,
  recomputed after the mandatory scroll-settle sleep (which itself
  consumes wall-clock time) so a tile can't overrun by up to one settle
  interval. Cap or skip the cosmetic per-tile animation wait the same
  way.
- Raise TiledScreenshotBudgetExceededError the moment the budget is
  exhausted -- before any further tile is captured -- and exempt it from
  the function's return-None fallback so callers fail the report loudly
  instead of receiving a partial/unchecked screenshot. No budget floor:
  a budget already exhausted by setup raises before the first tile,
  matching the non-tiled path's raise-before-capture semantics.
- Make the new error a subclass of ScreenshotTaskBudgetExceededError
  (moved to screenshot_utils.py, re-exported from webdriver.py) so
  callers can catch the whole budget-error family with one type.
- Enrich the per-tile timeout WARNING with budget context (waited vs
  requested load_wait, elapsed vs total budget, tiles captured) and add
  a per-tile DEBUG timing breakdown so slow dashboards can be profiled
  from logs alone.

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

alert-reports Namespace | Anything related to the Alert & Reports feature change:frontend Requires changing the frontend dashboard Namespace | Anything related to the Dashboard size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants