Skip to content

Improved Sentry diagnostics for Billing app load failures#27937

Merged
aileen merged 2 commits into
mainfrom
aileen/billing-load-monitor-diagnostics
May 18, 2026
Merged

Improved Sentry diagnostics for Billing app load failures#27937
aileen merged 2 commits into
mainfrom
aileen/billing-load-monitor-diagnostics

Conversation

@aileen
Copy link
Copy Markdown
Member

@aileen aileen commented May 18, 2026

ref INC-284
ref Sentry ADMIN-1BZQ — 439 events / 294 users

Summary

Billing app failed to become ready (ADMIN-1BZQ) currently lands in Sentry with very little context — we can't tell whether the iframe is being blocked, the network is offline, the BMA is hanging during boot, the iframe load event never fired, or the load monitor is firing while the iframe is still hidden behind the closed modal.

This PR enriches the existing Sentry capture in BillingService.reportBillingAppLoadFailure with the data needed to actually diagnose ADMIN-1BZQ. Added fields under contexts.ghost.billing_monitor:

  • document_visibility_state
  • iframe_offset_parent_visible, iframe_computed_display, iframe_computed_visibility, iframe_bounding_rect
  • bma_boot_probe{accessible, has_markReady, threw} against iframe.contentWindow.__bmaBoot
  • iframe_load_fired — whether the iframe's load event ever fired
  • ms_since_src_set — how long the parent has been waiting since iframe.src was assigned
  • navigator_online, connection_effective_type
  • billing_window_open

The event is also now reported at level: 'warning' (the user-facing error UI is rendered separately by gh-billing-modal, so a hard error is the wrong severity) with a stable fingerprint: ['billing-app-load-failure', visibilityState, attempts] so enriched events don't merge into the legacy bucket.

setBillingIframeSrc is extracted from gh-billing-iframe.js's setup() so both the initial render and the retry path consistently record billingAppIframeSrcSetAt and attach the load listener. No behavioral change to the monitor itself — same 10s timeout, same one retry.

Ship diagnostics, observe what the enriched events actually say, then make an informed behavioral change in a follow-up.

Test plan

  • pnpm exec eslint clean on changed files
  • Updated unit test asserts the new billing_monitor fields, the warning level, and the fingerprint; bma_boot_probe is asserted by key-shape (value depends on iframe presence)
  • Test stubs getBillingIframe to null for deterministic diagnostics (the previous CI failure was caused by a sibling test leaving an iframe in the DOM with id="billing-frame")
  • Manual: trigger a failure by blocking the BMA origin and confirm enriched fields appear in Sentry with level: warning

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4579fcf6-c3b6-4b28-a4be-ff0b3c95d55d

📥 Commits

Reviewing files that changed from the base of the PR and between 0724fdf and 0befe09.

📒 Files selected for processing (1)
  • ghost/admin/app/services/billing.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • ghost/admin/app/services/billing.js

Walkthrough

This PR enhances the billing service's iframe load tracking and failure diagnostics. It introduces state fields to track when the iframe src is set and whether the load event fires, adds a new setBillingIframeSrc() method to centralize iframe initialization with optional load event listener support, and expands the failure reporting to collect rich runtime diagnostics including iframe visibility, geometry, load state timing, and network connectivity. The component and reload logic are updated to use the new setter, and tests are expanded to validate the new tracking behavior and diagnostic reporting to Sentry.

Possibly related PRs

  • TryGhost/Ghost#27895: Adds @tracked decorators to billing load/failure flags to drive loading and error UI states in the component, building on the same billing readiness and error flow modified here.

Suggested reviewers

  • kevinansfield
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Improved Sentry diagnostics for Billing app load failures' accurately summarizes the main change in the PR, which is adding enhanced diagnostic context to Sentry error reporting for billing app failures.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation (ADMIN-1BZQ issue), the new diagnostic fields added, behavioral changes, and test plan.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch aileen/billing-load-monitor-diagnostics

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Comment @coderabbitai help to get the list of available commands and usage tips.

@aileen aileen force-pushed the aileen/billing-load-monitor-diagnostics branch from 53dd752 to 024da0e Compare May 18, 2026 10:02
@aileen aileen changed the title 🐛 Fixed false-positive Billing load error when pre-warmed iframe was hidden Improved Billing app load monitor with visibility gate and Sentry diagnostics May 18, 2026
@aileen aileen marked this pull request as draft May 18, 2026 10:02
@aileen aileen force-pushed the aileen/billing-load-monitor-diagnostics branch from 024da0e to c2135f6 Compare May 18, 2026 10:23
@aileen aileen requested a review from sam-lord May 18, 2026 10:26
@aileen aileen force-pushed the aileen/billing-load-monitor-diagnostics branch from c2135f6 to a6b49d5 Compare May 18, 2026 10:43
@aileen aileen changed the title Improved Billing app load monitor with visibility gate and Sentry diagnostics Improved Sentry diagnostics for Billing app load failures May 18, 2026
Copy link
Copy Markdown
Contributor

@sam-lord sam-lord left a comment

Choose a reason for hiding this comment

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

Looks good!

@aileen aileen marked this pull request as ready for review May 18, 2026 11:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@ghost/admin/app/services/billing.js`:
- Around line 111-116: The boolean _loadListenerAttached is global and can be
stale when the `#billing-frame` iframe is re-created, causing the new iframe to
miss its load handler and billingAppIframeLoadFired to be wrong; instead, check
and mark the listener on the iframe instance itself (e.g. set a property like
iframe.__loadListenerAttached or use iframe.dataset.loadListenerAttached) before
calling iframe.addEventListener('load', ...) and set that instance flag inside
the handler so each new iframe gets its own listener and
billingAppIframeLoadFired is updated reliably.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dc1ed012-2983-42b8-8481-e527f9dd5ebc

📥 Commits

Reviewing files that changed from the base of the PR and between 2241565 and a6b49d5.

📒 Files selected for processing (3)
  • ghost/admin/app/components/gh-billing-iframe.js
  • ghost/admin/app/services/billing.js
  • ghost/admin/tests/unit/services/billing-test.js

Comment thread ghost/admin/app/services/billing.js Outdated
ref [INC-284](https://app.incident.io/ghost/incidents/284)

Sentry ADMIN-1BZQ (439 events / 294 users) reports `Billing app failed to become ready` with very little context, making it hard to tell whether the iframe is being blocked, the network is offline, the BMA is hanging during boot, or the load monitor is firing while the iframe is still hidden. The Sentry capture in `BillingService.reportBillingAppLoadFailure` now records `document.visibilityState`, the iframe's `offsetParent` visibility, computed `display`/`visibility`, bounding rect, a `__bmaBoot` probe (`accessible` / `has_markReady` / `threw`), whether the iframe's `load` event fired, `ms_since_src_set`, `navigator.onLine`, `navigator.connection.effectiveType`, and `billingWindowOpen`. The event is now reported at `level: 'warning'` (the user-facing error UI is rendered separately by `gh-billing-modal`, so a hard error is the wrong severity) with a stable `fingerprint` keyed on visibility state and attempt count so the enriched buckets stay distinct from the legacy noise. `setBillingIframeSrc` is extracted so both the initial render and the retry path record `billingAppIframeSrcSetAt` and attach the `load` listener — no behavioral change to the monitor itself, which keeps its existing 10s timeout + 1 retry. The hypothesis that the parent-side timer needed a visibility gate (mirroring TryGhost/billing#1209) doesn't hold up: parent `setTimeout` is only throttled when the whole tab is backgrounded, and the Sentry tag distribution shows the failures are not concentrated on mobile, where hidden-iframe throttling would be most aggressive. Better to ship diagnostics first, see what the data actually says, then decide on a behavioral fix.
@aileen aileen force-pushed the aileen/billing-load-monitor-diagnostics branch from a6b49d5 to 0724fdf Compare May 18, 2026 11:40
ref [INC-284](https://app.incident.io/ghost/incidents/284)

Track the iframe instance the `load` listener was attached to instead of a
global boolean. If `#billing-frame` is ever re-created (Ember re-render or
HMR), the boolean would say "already attached" while the new iframe element
has no listener, leaving `billingAppIframeLoadFired` stuck and the Sentry
diagnostic misleading. Comparing against the iframe reference re-attaches
the listener whenever the element changes.

Addresses CodeRabbit review feedback on #27937.
@aileen aileen enabled auto-merge (squash) May 18, 2026 11:58
@aileen aileen merged commit 319d32d into main May 18, 2026
41 checks passed
@aileen aileen deleted the aileen/billing-load-monitor-diagnostics branch May 18, 2026 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants