-
Notifications
You must be signed in to change notification settings - Fork 387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(navigation): prevent updating ngrx state when no components received from backend #17673
Conversation
QA stepsWe need to simulate that OCC |
{ | ||
...{}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code cleanup is done by the way. it has nothing to do with the main purpose (bugfix) of this PR
4 flaky tests on run #41094 ↗︎
Details:
b2b/regression/checkout/b2b-credit-card-checkout-flow.core-e2e.cy.ts • 1 flaky test • B2B
ssr/pages.core-e2e.cy.ts • 3 flaky tests • SSR
This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. |
projects/storefrontapp-e2e-cypress/cypress/e2e/regression/cms/cms-navigation.core-e2e.cy.ts
Outdated
Show resolved
Hide resolved
projects/storefrontapp-e2e-cypress/cypress/e2e/regression/cms/cms-navigation.core-e2e.cy.ts
Outdated
Show resolved
Hide resolved
…ved from backend (#17673) Closes: https://jira.tools.sap/browse/CXSPA-4157
When the bug happens
The edge-case bug happens when OCC returns inconsistent responses among
/pages
API vs/components
API. In particular, when OCC/pages
API returns at least oneCmsLink
component (in the cms navigation) that the OCC/components
API has no idea about (so/components
API returns empty response when asked for details of this CmsLink component id), then SpartacusNavigationService
goes into infinite loop trying to load details of thisCmsLink
component over and over again.When this edge-case could happen in reality: when the cached APIs
/pages
and/components
had cache different invalidation times. The following is a detailed example:CmsLink
from theCmsNavigation
/pages
API was NOT YET invalidated, but the cache of/components
API was ALREADY invalidated. This means, that the stale/pages
API was still returning ID of the removedCmsLink
component as part of CMS page structure. But the up-to-date/components
API asked in a followup call for details of this component, didn't return any data, because this component no longer existed (was removed)./pages
API, and received in (stale cached) response the ID of this removed CmsLink (among also other navigation component IDs as usual)Then during the same render SSR called the endpoint
/components
asking for the details of thisCmsLink
, but the (up-to-date) API didn't return any details of this component.CmsLink
component via the/components
API over and over again.Note: such an infinite loop could happen regardless whether Spartacus runs in the browser (CSR) or in NodeJS (SSR).
Why Spartacus needs to load missing components?
One could ask: Why Spartacus bothers to load missing components from the
/components
API? Answer: there is a valid business usecase for it - components that are hidden for anonymous users (due to a CMS restriction mechanism), but visible for logged in users are considered "missing" when the user logs in, and their details need to be loaded after the user logs in. For more, see the old Spartacus github bug ticket: NavigationNodes(cx-category-navigation) with CMS restrictions(e.g. loggedInUser) not shown until a Browser refresh #5969., which introduced the logic of loading missing cms components' details.Why this PR prevents infinite loop?
Short answer: now we don't update ngrx state, when receiving empty response from
/components
OCC API. This breaks the circuit: load missing cms components -> received empty response -> update ngrx state -> load missing cms components -> ...Explanation: From Spartacus point of view, when
/pages
API returns IDs of components that are in the cms structure, then Spartacus tries to load details of all those components via/components
API. Currently, when/components
API returns an empty response for the given ID, the ngrx state object reference is updated despite that this empty response didn't actually changed the ngrx state - it's only the state's object reference that changed for no good reason. Such a change of object's reference triggers an emission of RxJs observable with this state. This leads to emiting a new value from the$data
observable in the stream returned byNavigationService.getNavigationNode()
. Inside the logic of this stream, Spartacus recognizes that some components's details are still missing, and therefore tries to load them by callingCmsService.loadNavigationItems(navigation.id, missingItems)
- see the source code of the branches release/4.3.1 and develop-6.3.x.In order to break the infinite loop, it suffices that we fix the Spartacus ngrx
navigation-item-entry.reducer.ts
(see its source code, which is the same in both branches: release/4.3.x and develop-6.3.x). The fixed version should check for thelength
of thecomponents
payload - if it's empty, then no state change should happen.fixes https://jira.tools.sap/browse/CXSPA-4157