Skip to content
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

[apiFetch] Fix preloading middleware referencing stale data #25550

Merged
merged 2 commits into from
Sep 24, 2020

Conversation

jeyip
Copy link
Contributor

@jeyip jeyip commented Sep 22, 2020

Description

Unblocks #25386

The logic for preloading middleware in the apiFetch library caches preloaded data. As it stands today, if an apiFetch request is made that matches a preloaded endpoint, it will reference the cache.

The problem is that the cache is never invalidated during a session. When updates are persisted to the WordPress database, the cache doesn't change, and requests to preloaded endpoints will continue to reference stale, preloaded data. This continues until a session has ended (browser is refreshed or closed).

Example of Unexpected Behavior:

  • We're trying to implement a feature where the user can update page title and page slug in the site editor
  • Upon saving changes to the page entity, local state is updated with the new title. This, however, is short lived.
  • In the Page Switcher component, there is a getEntityRecords( 'postType', 'page' ) selector. The selector resolution is invalidated because we've just persisted changes to the page title.
  • getEntityRecords( 'postType', 'page' ) will resolve an apiFetch request to /wp/v2/pages?context=edit, which is a preloaded path . This returns cached and stale preloaded data.
  • The UI reverts any page title updates to a previous state. It incorrectly presents data that was initially preloaded instead of a new page title.

Our solution is to only reference cached data a single time for each preloaded endpoint, after which subsequent requests skip preloading middleware.

Note:

I'm definitely going to lean on the expertise of others that have written code for the preloading middleware. This is my first time working extensively in the apiFetch library, and I'd appreciate any and all feedback 🙏

How has this been tested?

I tested these fixes on #25386. I'm not certain if there is a better way to do this. If anyone has better suggestions, feel free to let me know.

  1. Checkout the branch in Try/add page name to document settings [IN PROGRESS] #25386 called try/add_page_name_to_document_settings
  2. Spin up a local WordPress instance. From the project root:
    a. Execute npx wp-env start in the terminal
    b. Execute npm run dev in the terminal
  3. Open the WordPress UI at http://localhost:8888/wp-admin and sign in with the username admin and the password password.
  4. Enable site editing in the local dev environment
    a. Click on Appearance < Themes in the sidebar and activate the seedlet blocks theme
    b. Click on Gutenberg < Experiments in the sidebar and check the Full Site Editing Feature
  5. Set the home page as a static page
    a. Navigate to Settings > Reading > Your homepage displays
    b. Select "A static page" and assign "sample page"
  6. Navigate to the site editor from the wp-admin sidebar
  7. Verify problematic behavior
    a. Click on the topbar label called "singular"
    b. Type in a new page name
    c. Note how the title of the page also changes in content of the block editor
    d. Click on update design and then save
    e. Note how the title of the page reverts to "sample page", but updates correctly upon page refresh
  8. Verify bug fix
    a. Open another terminal window and execute git cherry-pick a570088 (pulls in the bug fix from this branch)
    b. Revisit the site editor (referesh the page if you haven't already)
    c. Click on the topbar label called "singular"
    d. Type in a new page name
    e. Note how the title of the page also changes in content of the block editor
    f. Click on update design and then save
    g. Note how the title of the page correctly reflects the newly updated value
    h. Execute git reset --hard HEAD~1 to revert to original branch state

Screenshots

Types of changes

Bug fix that is blocking #25386

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@jeyip jeyip added the [Type] Bug An existing feature does not function as intended label Sep 22, 2020
@jeyip jeyip self-assigned this Sep 22, 2020
@jeyip jeyip changed the title Fix api fetch referencing stale data [apiFetch] Fix preloading middleware referencing stale data Sep 22, 2020
@jeyip jeyip added the [Package] API fetch /packages/api-fetch label Sep 22, 2020
@github-actions
Copy link

github-actions bot commented Sep 22, 2020

Size Change: +29 B (0%)

Total Size: 1.17 MB

Filename Size Change
build/api-fetch/index.js 3.35 kB +11 B (0%)
build/block-editor/index.js 128 kB -8 B (0%)
build/block-library/index.js 135 kB +26 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.52 kB 0 B
build/autop/index.js 2.72 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 8.53 kB 0 B
build/block-directory/style-rtl.css 943 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/style-rtl.css 11.1 kB 0 B
build/block-editor/style.css 11.1 kB 0 B
build/block-library/editor-rtl.css 8.56 kB 0 B
build/block-library/editor.css 8.56 kB 0 B
build/block-library/style-rtl.css 7.6 kB 0 B
build/block-library/style.css 7.59 kB 0 B
build/block-library/theme-rtl.css 741 B 0 B
build/block-library/theme.css 741 B 0 B
build/block-serialization-default-parser/index.js 1.78 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 47.5 kB 0 B
build/components/index.js 167 kB 0 B
build/components/style-rtl.css 15.5 kB 0 B
build/components/style.css 15.5 kB 0 B
build/compose/index.js 9.42 kB 0 B
build/core-data/index.js 12 kB 0 B
build/data-controls/index.js 1.27 kB 0 B
build/data/index.js 8.43 kB 0 B
build/date/index.js 31.9 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 4.42 kB 0 B
build/edit-navigation/index.js 10.4 kB 0 B
build/edit-navigation/style-rtl.css 868 B 0 B
build/edit-navigation/style.css 871 B 0 B
build/edit-post/index.js 306 kB 0 B
build/edit-post/style-rtl.css 6.24 kB 0 B
build/edit-post/style.css 6.23 kB 0 B
build/edit-site/index.js 19.7 kB 0 B
build/edit-site/style-rtl.css 3.3 kB 0 B
build/edit-site/style.css 3.3 kB 0 B
build/edit-widgets/index.js 17.5 kB 0 B
build/edit-widgets/style-rtl.css 2.8 kB 0 B
build/edit-widgets/style.css 2.8 kB 0 B
build/editor/editor-styles-rtl.css 492 B 0 B
build/editor/editor-styles.css 493 B 0 B
build/editor/index.js 45.5 kB 0 B
build/editor/style-rtl.css 3.8 kB 0 B
build/editor/style.css 3.8 kB 0 B
build/element/index.js 4.45 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.49 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 1.74 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.55 kB 0 B
build/is-shallow-equal/index.js 709 B 0 B
build/keyboard-shortcuts/index.js 2.39 kB 0 B
build/keycodes/index.js 1.85 kB 0 B
build/list-reusable-blocks/index.js 3.02 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.12 kB 0 B
build/notices/index.js 1.69 kB 0 B
build/nux/index.js 3.27 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.44 kB 0 B
build/primitives/index.js 1.34 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 13.7 kB 0 B
build/server-side-render/index.js 2.61 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.24 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.74 kB 0 B
build/warning/index.js 1.13 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

The logic for preloading middleware in the apiFetch library caches preloaded data. As it stands today, all requests to the preloaded endpoint will reference the cache.

The problem is that the cache is never invalidated during a session. When updates are persisted to the WordPress database, the cache doesn't change, and it will continue to reference the stale, preloaded data.

This fix only allows references to cached data for each preloaded endpoint a single time, after which all subsequent requests to preloaded endpoints will skip preloading middleware.
@jeyip jeyip force-pushed the fix/api-fetch-preloading-stale-data branch from 0fd44f5 to a570088 Compare September 23, 2020 01:03
cache[ path ] &&
! cache[ path ].hasBeenPreloaded
) {
cache[ path ].hasBeenPreloaded = true;
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe instead of adding a boolean we can just unset the cache key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a great point! Unsetting would probably work as well and be less verbose. 👍

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

Seems logical, I wonder why we didn't hit this before :).

I wonder if it's dependent on the preloaded data and whether we need some kind of flag to say "number of uses", not sure it's needed though.

Did you check whether the number of API calls made when you load the post editor is the same before and after the PR? (with the document sidebar open)

@jeyip
Copy link
Contributor Author

jeyip commented Sep 23, 2020

Seems logical, I wonder why we didn't hit this before :).

Right?! This struck me as really odd. At least it's something we're catching now rather than later :P

Did you check whether the number of API calls made when you load the post editor is the same before and after the PR?

That's a great question! I did a quick once-over, but not with the sidebar open. Do you mean the document / block settings sidebar? I'll be sure to take another look tomorrow.

@youknowriad
Copy link
Contributor

Do you mean the document / block settings sidebar?

yes, and potentially with the "categories" and "tags" panel open as these do make some API request that might be cached as well.

Copy link
Contributor

@Addison-Stavlo Addison-Stavlo left a comment

Choose a reason for hiding this comment

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

I tested via the instructions and can confirm this fixes the issue. 😁

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

I didn't test but I think it looks good.

@jeyip
Copy link
Contributor Author

jeyip commented Sep 24, 2020

yes, and potentially with the "categories" and "tags" panel open as these do make some API request that might be cached as well.

I can confirm that the number of requests is the same when I compare fix/api-fetch-preloading-stale-data with master

@jeyip
Copy link
Contributor Author

jeyip commented Sep 24, 2020

@youknowriad I unset the cache key instead of adding the boolean. I also double-checked the total number of requests on master and with this branch. It's still the same 👍

Copy link
Member

@noahtallen noahtallen left a comment

Choose a reason for hiding this comment

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

This works perfectly with the new approach (invalidating the cache). Thanks for figuring this out! :shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] API fetch /packages/api-fetch [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants