Skip to content

Bound storefront config polling while unbound or connecting - #1518

Merged
sbolinger-godaddy merged 8 commits into
mainfrom
fix/storefront-bounded-config-polling
Oct 26, 2026
Merged

sbolinger-godaddy merged 8 commits into
mainfrom
fix/storefront-bounded-config-polling

Conversation

@sbolinger-godaddy

@sbolinger-godaddy sbolinger-godaddy commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

CommerceProvider polled GET /api/commerce/config every 5 seconds whenever the last response was unbound or connecting. Failed refreshes kept the last unbound data, so they didn't stop the interval either. In production, every open tab of a site with no store kept polling indefinitely.

Why this approach

A user may select a template that has no store bound. They may never connect a store, or they may connect one minutes, hours or days later. So the goal isn't to wait until a store connects. It's to make sure we never poll indefinitely in production.

To do that, polling ends on a fixed schedule, and a page refresh starts it again. Polling is frequent right after a refresh, when the user is most likely to be connecting a store, then backs off over 30 minutes. A request cap or a more complex backoff was not needed, so the schedule is deliberately simple.

Change

refetchInterval is now timed from when the provider mounts, which is when the page loads:

  • 0–5 min: every 5 s
  • 5–30 min: every 60 s
  • after 30 min: stop

Reloading the page or retryConnection() starts polling again. Focus still refreshes once. These are unchanged: samples, the connecting failure grace, stale data never granting readiness, and no polling in background tabs. Failures don't extend the window.

A page still connecting when polling stops shows the connection error with "Retry connection" instead of "Connecting to the store…" indefinitely. Retrying shows connecting again and starts a new polling period, like a reload. Only a host's readConnectionState() can report connecting, so catalog API outages can't cause this.

A failed retry shows "Connecting to the store…" for at least a second before the error returns. Before, a fast failure re-rendered the same error, so the button looked like it did nothing. Retrying without an error (retryConnection() is public on useCommerce()) only refreshes, so a connected cart or sample cart isn't reset.

A change in the reported state also starts a new polling window. A merchant who leaves an unbound tab open past 30 minutes and connects a store elsewhere gets connecting on the focus refresh, and polling resumes instead of showing "taking too long" right away.

Tests

  • Polling backs off after 5 minutes and stops at 30, including after failed refreshes, with no requests over the next day.
  • A store connected while backed off (20 minutes in) is picked up.
  • A remount after polling stops starts polling again.
  • A page still connecting at 30 minutes offers a retry. Retrying shows connecting again, polls every 5 s, stops again at 30 minutes, and a later retry picks up ready.
  • A retry that fails shows connecting for a second, then the error. The test fails against the previous code (expected 'error' to be 'connecting').
  • Retrying on a connected page keeps the state ready and the cart unchanged. Against the previous commit: expected 'connecting' to be 'ready'.
  • unbound past 30 minutes, then a focus refresh finding connecting, polls again and picks up ready. Against the previous commit: expected 'error' to be 'connecting'.

The stopping test fails against the previous refetchInterval (expected 121 to be 66). The other two pass on both versions, as expected. lint, typecheck, build and all 127 package tests pass.

🤖 Generated with Claude Code

A site with no connected store reports `unbound` until it is republished,
so every visible tab requested /config every five seconds indefinitely,
and failed refreshes kept the interval running. Poll every five seconds
for two minutes, then every 30 seconds, and stop after fifteen minutes.
`connecting` should end soon, so it polls fast for five minutes and stops
after 30. Each limit counts from when the page first saw that state.
Mount and visibility refetches still recover, and visibility starts a new
polling period.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c46a3d8

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@godaddy/gd-commerce-storefront Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@sbolinger-godaddy
sbolinger-godaddy requested a review from a team as a code owner October 23, 2026 17:31
sbolinger-godaddy and others added 2 commits October 23, 2026 10:39
Stop polling after a fixed number of /config results, failures included,
counted by React Query: 180 (about fifteen minutes) unbound and 360
(about thirty) connecting. This bounds polling with a much smaller change
than the backoff schedule and visibility tracking it replaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A site can stay unbound for days, so a request cap or focus-based restart
does not fit. Time polling from page load instead: every five seconds for
five minutes, then every minute, and stop at thirty minutes. Reloading the
page starts it again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@wcole1-godaddy wcole1-godaddy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the polling implementation, surrounding connection handling, documentation, and regression tests. No blocking findings. The mount-relative deadline bounds repeated configuration requests even when refreshes fail, without resetting the budget on retry/focus or changing readiness eligibility. The tradeoff that a store connected after the window needs a focus refresh, explicit retry, or remount/reload is intentional and reasonable for this fix.

Validated locally at 4e2d798: package build, all 126 tests, typecheck, and lint pass.

Optional follow-ups: (1) describe timing as relative to provider mount rather than page load, since an SPA can mount/remount it without a reload; (2) strengthen the polling test with an expected request count at the 30-minute boundary (the existing long-idle assertion proves it stops by then, not that it continues until then), plus connecting-state and post-cutoff focus/retry cases. These are non-blocking.

sbolinger-godaddy and others added 5 commits October 23, 2026 10:53
A page still connecting at thirty minutes shows the connecting message
until focus or reload. Once polls are a minute apart, the 60-second
connecting grace has already passed at the next failure, so the error
shows at once. Rewrap the edited paragraphs to the surrounding width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Once polling stops, nothing refreshes a page that is still connecting, so
it showed "Connecting to the store…" with no way forward. Report it as a
connection error with "Retry connection".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Retry refetched once, but polling stayed stopped, so a page still
connecting went straight back to the error. Retrying now starts a new
polling period, so the page shows connecting again and polls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… polling when the reported state changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sbolinger-godaddy
sbolinger-godaddy merged commit 408ad4a into main Oct 26, 2026
3 checks passed
@sbolinger-godaddy
sbolinger-godaddy deleted the fix/storefront-bounded-config-polling branch October 26, 2026 16:08
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