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

Autosave changes disappearing and speed improvement #51065

Closed
wants to merge 11 commits into from

Conversation

malomalo
Copy link
Contributor

Motivation / Background

When autosave: true is set on both ends of a relation save and/or valid? can be called more than once removing the changes that just happened during the current save and making previous_changes and empty hash.

Additionally when there is a lot of records in memory save on a sub record can be called a significant amount of times. It seem that the child models are saved and validated in every permutation possible. This PR results in every record being called at most 1 time and can significantly reduce CPU usage and time to save in this situations.

Detail

This PR adds memory to ensure that each record only gets saved and/or validated only once while traversing the autosave tree, ensuring the changes are available after saving via the previous_changes method.

Fixes #28491.

#28491 suggested adding a variable to avoid clearing the changes on the root record which worked; but would not fix the issue if the two models with the autosave true are related to another separate model that is being saved or updated.

Fixes #46438.

This PR also supplants #46438 and enhances it by being able to work across connections and increase speed by only allowing autosaved child models to be saved or validated only once.

Checklist

  • This Pull Request is related to one change. Changes that are unrelated should be opened in separate PRs.
  • Commit message has a detailed description of what changed and why. If this PR fixes a related issue include it in the commit message. Ex: [Fix #issue-number]
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature. Minor bug fixes and documentation changes should not be included.
  • CI is passing.

* main: (39 commits)
  Address `ActiveStorage::VariantTest#test_resized_variation_of_WEBP_blob` failure at Rails Nightly CI
  doc: Warn against having uniqueness validator when create_or_find_by is used
  [Fix rails#50604] Restore compatibility of ARE configs with eager loading mode
  ActionDispatch::Executor: report errors handled by ShowExceptions
  docker-entrypoint: export LD_PRELOAD
  Update create has_one failure test descriptions
  Update 7.0 release notes re inflections and the once autoloader
  Fix deprecated `enum` syntax in tests
  Deprecate defining enums with keywords args
  Fix configuration order
  Add note about imagemagick / libvips support being required
  Add WebP as a new framework default image type
  Add class name to enum validation exception message
  Update activestorage/app/models/active_storage/blob/representable.rb
  Transform actionpack documentation to Markdown
  docs:expand documentation on has_one_attached method.
  Disambiguate language around when code stops re: `redirect_to`
  Prefer to reference git's default configuration, not bespoke
  Fixes race condition when multiple preprocessed variants are defined for a Previewable file is attached
  Parse tests with prism
  ...
Copy link
Member

@rafaelfranca rafaelfranca left a comment

Choose a reason for hiding this comment

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

The size of this patch and the complexity of it points to me that this issue is being solved in the wrong layer. It seems like we are missing a better abstraction than passing a hash around and checking it everywhere.

@malomalo
Copy link
Contributor Author

This solution solves both of those and still allow people to call save in after_save and after_validation callbacks. 😱. In the past PR I've tried it on a connection variable but that is also not the right place. This is my ~4ish iteration on this issue, either because of changes that disappear or significant resources spent traversing the autosave tree. We've been running this as a monkey patch for this for the last few months and the previous PR for years.

I'm open to ideas on how to improve it, I assume you mean adding another module similar to ActiveRecord::Validations?

@rafaelfranca
Copy link
Member

It is hard to provide ideas on how to improve because this is reaching for too much. Passing this hash around for so many methods in Rails is a no go. I don't have right now another suggestion, but I just want to make it clear that a solution like this would never be merged.

All that complexity added to save, save! and valid? even if it was moved to a different module is file isn't good. We should not need to have an exposed cache like this one.

There are many avenues to try here. Maybe there is an abstraction that is missing (see as example AttributeSet). Maybe there are other ways than caching objects id to know if validation were run on not.

@rafaelfranca
Copy link
Member

Actually. I'll close the PR since we will not merge this one. In the case you are interested on building a good solution for the problem, we can open new ones. I really appreciate you spending time trying to fix this issue, but this isn't a good solution.

@malomalo
Copy link
Contributor Author

Leaving this gist here for anyone who has the same issue or think they might. You can just add this to an ext folder in your Rails app and require it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

previous_changes is empty if two models have autosave: true for each other
2 participants