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

Fixed-schedule AutosaveMonitor #23962

Merged
merged 16 commits into from
Jul 30, 2020
Merged

Conversation

adamziel
Copy link
Contributor

@adamziel adamziel commented Jul 15, 2020

Description

The current AutosaveMonitor does not consistently execute autosaves in response to user input.

This PR proposes a completely different approach. Instead of trying to get scheduling and cancelling right, we:

  • Store one boolean flag: needsAutosave and flip it to true or false anytime something relevant happens.
  • Always run a handler every 60 seconds. If the flag is true, autosave.
  • If the handler is running at a time when isAutosaveable is false, keep retrying every 1 second.

As a result, autosave will be executed at most 60 seconds after the first unsaved input, sometimes less.

How has this been tested?

Unit tests are failing now - I'd like to have some discussion about the approach before spending time on adjusting them.

For manual testing, see the instructions below:

Default autosave interval is 60 seconds, if you want to save some time you could modify line 81 to say interval: 4, instead of just interval,. Then:

  • Create a new post or open an existing one.
  • Start typing and then stop, confirm the autosave kicks in within a minute (or 4 seconds).
  • Confirm there is no subsequent autosave after another minute if you don't type anything again.
  • Type something else, confirm the autosave worked.
  • Keep typing while the autosave is going and confirm another one happened.
  • Type something, save the post manually, don't type anything else, confirm no autosave was triggered.

Types of changes

Bug fix (non-breaking change which fixes an issue)

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.

@adamziel adamziel added [Type] Bug An existing feature does not function as intended [Feature] Saving Related to saving functionality [Feature] History History, undo, redo, revisions, autosave. labels Jul 15, 2020
@adamziel adamziel requested review from mcsf, youknowriad and aduth July 15, 2020 15:40
@adamziel adamziel self-assigned this Jul 15, 2020
prevProps.editsReference !== editsReference
isDirty &&
isAutosaveable &&
! didAutosaveForEditsReference.current
Copy link
Contributor

Choose a reason for hiding this comment

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

It's very unclear to me why this check is necessary? Why not just always "schedule an autosave on each edit change"?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the reason is because you have "cancelSave" as an API to call explicitely while IMO, it should be handled internally in useScheduleSave. Basically if there's a new scheduled autosave while one is awaiting to be triggered, cancel it and schedule the new one instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the new approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Basically if there's a new scheduled autosave while one is awaiting to be triggered, cancel it and schedule the new one instead.

This would be the same as the current debounced approach which causes long periods without an autosave as long as the user is typing. As discussed in the issue, we don't need to limit the amount of these requests as the autosave would amend the last autosaved revision instead of creating a new one every time.

I want to make it so once an autosave is scheduled, no subsequent change would cancel it. It simply stays scheduled at a fixed point in time, and can only be cancelled if the AutosaveMonitor is told it shouldn't act (e.g. isAutosaveable == false).

I am struggling with the number of corner cases to handle though and have an idea for a much simpler and more bullet-proof approach - I will update this PR soon to show exactly what I mean.

@github-actions
Copy link

github-actions bot commented Jul 16, 2020

Size Change: -16 B (0%)

Total Size: 1.16 MB

Filename Size Change
build/core-data/index.js 11.8 kB +4 B (0%)
build/editor/index.js 45.3 kB -20 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.67 kB 0 B
build/api-fetch/index.js 3.44 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 7.93 kB 0 B
build/block-directory/style-rtl.css 953 B 0 B
build/block-directory/style.css 952 B 0 B
build/block-editor/index.js 125 kB 0 B
build/block-editor/style-rtl.css 10.8 kB 0 B
build/block-editor/style.css 10.8 kB 0 B
build/block-library/editor-rtl.css 7.63 kB 0 B
build/block-library/editor.css 7.63 kB 0 B
build/block-library/index.js 133 kB 0 B
build/block-library/style-rtl.css 7.83 kB 0 B
build/block-library/style.css 7.83 kB 0 B
build/block-library/theme-rtl.css 728 B 0 B
build/block-library/theme.css 729 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 48.2 kB 0 B
build/components/index.js 200 kB 0 B
build/components/style-rtl.css 15.7 kB 0 B
build/components/style.css 15.7 kB 0 B
build/compose/index.js 9.68 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.45 kB 0 B
build/date/index.js 5.38 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 3.23 kB 0 B
build/edit-navigation/index.js 10.9 kB 0 B
build/edit-navigation/style-rtl.css 1.08 kB 0 B
build/edit-navigation/style.css 1.08 kB 0 B
build/edit-post/index.js 304 kB 0 B
build/edit-post/style-rtl.css 5.61 kB 0 B
build/edit-post/style.css 5.61 kB 0 B
build/edit-site/index.js 17 kB 0 B
build/edit-site/style-rtl.css 3.06 kB 0 B
build/edit-site/style.css 3.06 kB 0 B
build/edit-widgets/index.js 9.38 kB 0 B
build/edit-widgets/style-rtl.css 2.45 kB 0 B
build/edit-widgets/style.css 2.45 kB 0 B
build/editor/editor-styles-rtl.css 537 B 0 B
build/editor/editor-styles.css 539 B 0 B
build/editor/style-rtl.css 3.8 kB 0 B
build/editor/style.css 3.79 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.72 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 2.13 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 711 B 0 B
build/keyboard-shortcuts/index.js 2.52 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.11 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.33 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 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.56 kB 0 B
build/primitives/index.js 1.41 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.9 kB 0 B
build/server-side-render/index.js 2.71 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@adamziel adamziel changed the title Throttled AutosaveMonitor Fixed schedule AutosaveMonitor Jul 16, 2020
@adamziel adamziel marked this pull request as ready for review July 16, 2020 14:46
@adamziel adamziel requested a review from nerrad as a code owner July 16, 2020 14:46
Comment on lines +625 to +667
( state ) => [
state.undo.length,
state.undo.offset,
state.undo.flattenedUndo,
]
Copy link
Contributor Author

@adamziel adamziel Jul 16, 2020

Choose a reason for hiding this comment

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

Without this change the selector is not being updated in response to continued typing within the same paragraph block. This means the AutosaveMonitor is unaware of unsaved edits. It seems like a bug to me but I'm curious about your thoughts @youknowriad.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch, it's a weird way to detect dirtiness though, I wonder if the component should rely on __experimentalGetDirtyEntityRecords instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a weird way. I suppose it was invented to account for the fact that autosaving doesn't make the post "not dirty" which also affects the isDirty prop this component receives. I just tested and the same is true for __experimentalGetDirtyEntityRecords - after an autosave completes, it still returns a non-empty list.

@adamziel
Copy link
Contributor Author

@youknowriad @mcsf Would you mind taking a look at this PR and sharing your thoughts? Ignore failing tests - I'm stalling until we agree on the approach here.

@adamziel adamziel changed the title Fixed schedule AutosaveMonitor Fixed-schedule AutosaveMonitor Jul 16, 2020
@youknowriad
Copy link
Contributor

I like this approach, it works as intended for me. it might be good to document the behavior somewhere. Maybe a comment on the component.

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.

LGTM 👍

@mcsf
Copy link
Contributor

mcsf commented Jul 28, 2020

Sorry for dropping the ball and not helping here, guys.

@adamziel adamziel force-pushed the update/make-autosave-timer-more-reliable branch from 799bb38 to c109577 Compare July 29, 2020 13:22
@adamziel adamziel merged commit 6cce6e0 into master Jul 30, 2020
@adamziel adamziel deleted the update/make-autosave-timer-more-reliable branch July 30, 2020 09:13
@github-actions github-actions bot added this to the Gutenberg 8.7 milestone Jul 30, 2020
delete this.pendingSave;
autosaveTimerHandler() {
if ( ! this.props.isAutosaveable ) {
this.setAutosaveTimer( 1000 );
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this fixed 1000 number correct? Shouldn't this take "interval" into consideration?

Copy link
Contributor Author

@adamziel adamziel Aug 23, 2021

Choose a reason for hiding this comment

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

It could be either 1000 or interval depending on how you look at it. Was there a bug report related to this?

A case for 1000:

  • We are not autosaveable and, from the perspective of this component, we don't know why – could be save in progress, could be internet connectivity issues
  • We want to know when we are saveable again as soon as possible because the interval could be 30 seconds and we could be intermittently non-autosaveable again on the next run. This would result in missing one or more autosave() calls.

A case for interval:

  • The handler explicitly asked the timer to run at most once per interval seconds
  • The handler is responsible for handling isAutosaveable property so it should already know if we missed an autosave() call

Copy link
Contributor

Choose a reason for hiding this comment

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

No, no bug, just looked weird. I was working on something unrelated requiring disabling autosave when I found it. Thanks for the explanation, it makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] History History, undo, redo, revisions, autosave. [Feature] Saving Related to saving functionality [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants