Performance: Optimize handling of content type updates#21910
Conversation
…ed, in-memory cache eviction
…checking publish status
…gged by content type.
There was a problem hiding this comment.
I've made a few changes and additions to the PR @kjac, so please see below to make sure you are happy with them and agree they are all necessary. I've tested and see the expected updates happening - content is still successfully retrieved from the cache and depending on the type of updates made, I'm seeing the expected calls to invalidate caches.
Here the changes made during review:
1. Auto-factory-aware converted cache clearing (ContentTypeCacheRefresher)
When using InMemoryAuto models builder mode, WithSafeLiveFactoryReset resets the entire model factory - invalidating ALL compiled model types, not just the changed ones. This means selectively clearing only specific content type IDs from _publishedContentCache is insufficient: parent content of different types would remain cached as stale instances withinvalidated model types, returning null.
I picked this up as I had the following code in my view:
var defaultCurrency = Model.Parent<Products>().DefaultCurrency;
And after a content type update - structural or non-structural Model.Parent<Products>() would return null.
The fix checks _publishedModelFactory is IAutoPublishedModelFactory and uses:
- Auto mode:
ClearConvertedContentCache()(full clear) - because the factory reset invalidates all model types - Non-auto mode:
ClearConvertedContentCache(contentTypeIds)(selective) - because model types are stable, only affected types need clearing
2. Do the same for DataTypeCacheRefresher
I found the same issue if I changed a data type used on a document type that a rendered page is based on, and applied a similar fix,
3. Additional test coverage
I added some unit tests and a few integration tests to increase code coverage for the logic introduced.
4. IOptionsMonitor.OnChange memory leak fix
See inline comment on this.
ContentTypeIndexingNotificationHandler subscribed to IOptionsMonitor.OnChange in its constructor but never disposed the subscription. Since notification handlers are transient, each instantiation leaked a subscription.
Fixed by storing IOptionsMonitor<IndexingSettings> and reading .CurrentValue at call time instead of subscribing to changes.
5. Added a migration to rebuild HybridCache
Pre-existing HybridCache entries lack the new ct:{id} / mt:{id} tags needed for tag-based eviction. Added a migration that clears and re-seeds the in-memory cache using ClearMemoryCacheAsync.
src/Umbraco.Infrastructure/Search/ContentTypeIndexingNotificationHandler.cs
Outdated
Show resolved
Hide resolved
* Backport #21910 to V13 * Update src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.ContentType.cs Co-authored-by: Andy Butland <abutland73@gmail.com> * Backport #21856 as well * Fix issue where removing a property type wasn't detecting and returning the expected change type. --------- Co-authored-by: Andy Butland <abutland73@gmail.com>
Updated [Umbraco.Cms.Persistence.Sqlite](https://github.com/umbraco/Umbraco-CMS) from 17.2.2 to 17.3.0. <details> <summary>Release notes</summary> _Sourced from [Umbraco.Cms.Persistence.Sqlite's releases](https://github.com/umbraco/Umbraco-CMS/releases)._ ## 17.3.0 ## Upgrade Notes In 17.3 we have upgraded our dependency on `MailKit` to 4.15.1. This is a minor version update, but we found a few changes we had to make in core to accommodate changes to nullability constraints. Unless using methods of this library, or it's transitive dependency `MimeKit`, it's unlikely projects will be affected. The update is necessary though, as the version we previously depended on now has a security vulnerability raised against it. We have made a change to how we handle redirects which brings a significant performance improvement for publish time on large sites, when documents with many descendent nodes are published. If you have custom URL providers you should review this change, as there are some [very rare cases](umbraco/Umbraco-CMS#22091 (comment)) where you'll need to adjust to ensure descendent redirects are correctly handled. Note also that we now auto-generate HMAC secret key for new installs. This has been applied to make Umbraco more secure by default, but it's not been forced for upgrades. ## What's Changed Since 17.3.0-rc3 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc3...release-17.3.0 ## What's Changed Since 17.3.0-rc2 ### 📦 Dependencies * Dependencies: Update Microsoft packages to latest patch and fix HybridCache ParseFault with Redis by @AndyButland in umbraco/Umbraco-CMS#22278 ### 🐛 Bug Fixes * Examine: Fix DocumentUrlService not initialized during Examine indexing after package upgrade by @AndyButland in umbraco/Umbraco-CMS#22243 * Unattended Upgrades: Rebuild routing caches after background migrations to fix unrouteable document URLs by @AndyButland in umbraco/Umbraco-CMS#22269 * Migrations: Fix NPoco auto-select breaking re-trust FK migration by @AndyButland in umbraco/Umbraco-CMS#22270 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc2...release-17.3.0-rc3 ## What's Changed Since 17.3.0-rc1 ### 🐛 Bug Fixes * Migrations: Fix re-trust constraints migration targeting non-Umbraco tables and transaction failure (closes #22227) by @AndyButland in umbraco/Umbraco-CMS#22229 * Distributed Locking: Add ROWLOCK hint to prevent cross-row contention on umbracoLock table (closes #22113) by @AndyButland in umbraco/Umbraco-CMS#22126 * Application URLs: Prevent back office hosts being overwritten in a shared database setup (closes #16741) by @matthewcare in umbraco/Umbraco-CMS#22160 * Migrations: Fix property detection for invariant content types with culture-varying compositions (closes #22159) by @AndyButland in umbraco/Umbraco-CMS#22167 * Migrations: Fix package migrations not running after fresh install with packages (closes #22202) by @AndyButland in umbraco/Umbraco-CMS#22204 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc...release-17.3.0-rc2 ## What's Changed Since the Previous Version (17.2.2) ### 🙌 Notable Changes * Templates: Add optional Central Package Management support to UmbracoProject and UmbracoExtension templates by @NguyenThuyLan in umbraco/Umbraco-CMS#21641 * Service registration: Allow running Umbraco with different combinations of backoffice, website and delivery API (closes #21622) by @AndyButland in umbraco/Umbraco-CMS#21630 * Imaging Configuration: Auto-generate HMAC secret key for new installs by @AndyButland in umbraco/Umbraco-CMS#21976 * Migrations: Run unattended upgrades in background, add liveness/readiness health probes (closes #21987) by @AndyButland in umbraco/Umbraco-CMS#22020 ### 💥 Breaking Changes * Dependencies: Update MailKit to 4.15.1 by @AndyButland in umbraco/Umbraco-CMS#22028 ### 📦 Dependencies * Bump lodash from 4.17.21 to 4.17.23 in /tests/Umbraco.Tests.AcceptanceTest in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21519 ... (truncated) ## 17.3.0-rc3 ## Upgrade Notes In 17.3 we have upgraded our dependency on `MailKit` to 4.15.1. This is a minor version update, but we found a few changes we had to make in core to accommodate changes to nullability constraints. Unless using methods of this library, or it's transitive dependency `MimeKit`, it's unlikely projects will be affected. The update is necessary though, as the version we previously depended on now has a security vulnerability raised against it. We have made a change to how we handle redirects which brings a significant performance improvement for publish time on large sites, when documents with many descendent nodes are published. If you have custom URL providers you should review this change, as there are some [very rare cases](umbraco/Umbraco-CMS#22091 (comment)) where you'll need to adjust to ensure descendent redirects are correctly handled. Note also that we now auto-generate HMAC secret key for new installs. This has been applied to make Umbraco more secure by default, but it's not been forced for upgrades. ## What's Changed Since 17.3.0-rc2 ### 📦 Dependencies * Dependencies: Update Microsoft packages to latest patch and fix HybridCache ParseFault with Redis by @AndyButland in umbraco/Umbraco-CMS#22278 ### 🐛 Bug Fixes * Examine: Fix DocumentUrlService not initialized during Examine indexing after package upgrade by @AndyButland in umbraco/Umbraco-CMS#22243 * Unattended Upgrades: Rebuild routing caches after background migrations to fix unrouteable document URLs by @AndyButland in umbraco/Umbraco-CMS#22269 * Migrations: Fix NPoco auto-select breaking re-trust FK migration by @AndyButland in umbraco/Umbraco-CMS#22270 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc2...release-17.3.0-rc3 ## What's Changed Since 17.3.0-rc1 ### 🐛 Bug Fixes * Migrations: Fix re-trust constraints migration targeting non-Umbraco tables and transaction failure (closes #22227) by @AndyButland in umbraco/Umbraco-CMS#22229 * Distributed Locking: Add ROWLOCK hint to prevent cross-row contention on umbracoLock table (closes #22113) by @AndyButland in umbraco/Umbraco-CMS#22126 * Application URLs: Prevent back office hosts being overwritten in a shared database setup (closes #16741) by @matthewcare in umbraco/Umbraco-CMS#22160 * Migrations: Fix property detection for invariant content types with culture-varying compositions (closes #22159) by @AndyButland in umbraco/Umbraco-CMS#22167 * Migrations: Fix package migrations not running after fresh install with packages (closes #22202) by @AndyButland in umbraco/Umbraco-CMS#22204 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc...release-17.3.0-rc2 ## What's Changed Since the Previous Version (17.2.2) ### 🙌 Notable Changes * Templates: Add optional Central Package Management support to UmbracoProject and UmbracoExtension templates by @NguyenThuyLan in umbraco/Umbraco-CMS#21641 * Service registration: Allow running Umbraco with different combinations of backoffice, website and delivery API (closes #21622) by @AndyButland in umbraco/Umbraco-CMS#21630 * Imaging Configuration: Auto-generate HMAC secret key for new installs by @AndyButland in umbraco/Umbraco-CMS#21976 * Migrations: Run unattended upgrades in background, add liveness/readiness health probes (closes #21987) by @AndyButland in umbraco/Umbraco-CMS#22020 ### 💥 Breaking Changes * Dependencies: Update MailKit to 4.15.1 by @AndyButland in umbraco/Umbraco-CMS#22028 ### 📦 Dependencies * Bump lodash from 4.17.21 to 4.17.23 in /tests/Umbraco.Tests.AcceptanceTest in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21519 * Bump the npm_and_yarn group across 2 directories with 2 updates by @dependabot[bot] in umbraco/Umbraco-CMS#21754 * Bump qs from 6.14.1 to 6.14.2 in /src/Umbraco.Web.UI.Client in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21755 * Dependencies: Bumps @umbraco-ui/uui from 1.17.0 to 1.17.1 by @iOvergaard in umbraco/Umbraco-CMS#22029 * Dependencies: Updates @umbraco-ui/uui to 1.17.2 to fix multiple folder drag-and-drop failing (closes #21837) by @iOvergaard in umbraco/Umbraco-CMS#21886 ... (truncated) ## 17.3.0-rc2 ## Upgrade Notes In 17.3 we have upgraded our dependency on `MailKit` to 4.15.1. This is a minor version update, but we found a few changes we had to make in core to accommodate changes to nullability constraints. Unless using methods of this library, or it's transitive dependency `MimeKit`, it's unlikely projects will be affected. The update is necessary though, as the version we previously depended on now has a security vulnerability raised against it. We have made a change to how we handle redirects which brings a significant performance improvement for publish time on large sites, when documents with many descendent nodes are published. If you have custom URL providers you should review this change, as there are some [very rare cases](umbraco/Umbraco-CMS#22091 (comment)) where you'll need to adjust to ensure descendent redirects are correctly handled. Note also that we now auto-generate HMAC secret key for new installs. This has been applied to make Umbraco more secure by default, but it's not been forced for upgrades. ## What's Changed Since 17.3.0-rc1 ### 🐛 Bug Fixes * Migrations: Fix re-trust constraints migration targeting non-Umbraco tables and transaction failure (closes #22227) by @AndyButland in umbraco/Umbraco-CMS#22229 * Distributed Locking: Add ROWLOCK hint to prevent cross-row contention on umbracoLock table (closes #22113) by @AndyButland in umbraco/Umbraco-CMS#22126 * Application URLs: Prevent back office hosts being overwritten in a shared database setup (closes #16741) by @matthewcare in umbraco/Umbraco-CMS#22160 * Migrations: Fix property detection for invariant content types with culture-varying compositions (closes #22159) by @AndyButland in umbraco/Umbraco-CMS#22167 * Migrations: Fix package migrations not running after fresh install with packages (closes #22202) by @AndyButland in umbraco/Umbraco-CMS#22204 **Full Changelog**: umbraco/Umbraco-CMS@release-17.3.0-rc...release-17.3.0-rc2 ## What's Changed Since the Previous Version (17.2.2) ### 🙌 Notable Changes * Templates: Add optional Central Package Management support to UmbracoProject and UmbracoExtension templates by @NguyenThuyLan in umbraco/Umbraco-CMS#21641 * Service registration: Allow running Umbraco with different combinations of backoffice, website and delivery API (closes #21622) by @AndyButland in umbraco/Umbraco-CMS#21630 * Imaging Configuration: Auto-generate HMAC secret key for new installs by @AndyButland in umbraco/Umbraco-CMS#21976 * Migrations: Run unattended upgrades in background, add liveness/readiness health probes (closes #21987) by @AndyButland in umbraco/Umbraco-CMS#22020 ### 💥 Breaking Changes * Dependencies: Update MailKit to 4.15.1 by @AndyButland in umbraco/Umbraco-CMS#22028 ### 📦 Dependencies * Bump lodash from 4.17.21 to 4.17.23 in /tests/Umbraco.Tests.AcceptanceTest in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21519 * Bump the npm_and_yarn group across 2 directories with 2 updates by @dependabot[bot] in umbraco/Umbraco-CMS#21754 * Bump qs from 6.14.1 to 6.14.2 in /src/Umbraco.Web.UI.Client in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21755 * Dependencies: Bumps @umbraco-ui/uui from 1.17.0 to 1.17.1 by @iOvergaard in umbraco/Umbraco-CMS#22029 * Dependencies: Updates @umbraco-ui/uui to 1.17.2 to fix multiple folder drag-and-drop failing (closes #21837) by @iOvergaard in umbraco/Umbraco-CMS#21886 * Backoffice: Update vite from 7.1.11 to 7.3.1 by @iOvergaard in umbraco/Umbraco-CMS#22065 * Dependencies: Update server-side dependencies to latest patch or minor releases by @AndyButland in umbraco/Umbraco-CMS#21860 ### 🚤 Performance * Performance: Implement key-based caching for data type and template repositories by @AndyButland in umbraco/Umbraco-CMS#21280 * Management API: Optimize collection view performance by eliminating N+1 patterns by @AndyButland in umbraco/Umbraco-CMS#21684 * Performance: Optimize handling of content type updates by @kjac in umbraco/Umbraco-CMS#21910 * Backoffice Performance: Add inflight request deduplication to item data request managers by @madsrasmussen in umbraco/Umbraco-CMS#21767 * URL and Alias Caches: Optimize for invariant documents by @AndyButland in umbraco/Umbraco-CMS#21558 * Custom Views: Prevent re-rendering Block Views and Properties by @rickbutterfield in umbraco/Umbraco-CMS#21186 * Core: Minimize await to a single JS cycle (refactor #21186) by @nielslyngsoe in umbraco/Umbraco-CMS#22074 * Auth: Skip /token refresh when access token is still valid by @iOvergaard in umbraco/Umbraco-CMS#22087 * Memory Management: Dispose `IDisposable` resources correctly in four internal classes by @AndyButland in umbraco/Umbraco-CMS#22014 * Redirect Tracking: Fix segment change detection and optimise descendant traversal (closes #22082) by @AndyButland in umbraco/Umbraco-CMS#22091 ... (truncated) ## 17.3.0-rc ## Upgrade Notes In 17.3 we have upgraded our dependency on `MailKit` to 4.15.1. This is a minor version update, but we found a few changes we had to make in core to accommodate changes to nullability constraints. Unless using methods of this library, or it's transitive dependency `MimeKit`, it's unlikely projects will be affected. The update is necessary though, as the version we previously depended on now has a security vulnerability raised against it. We have made a change to how we handle redirects which brings a significant performance improvement for publish time on large sites, when documents with many descendent nodes are published. If you have custom URL providers you should review this change, as there are some [very rare cases](umbraco/Umbraco-CMS#22091 (comment)) where you'll need to adjust to ensure descendent redirects are correctly handled. Note also that we now auto-generate HMAC secret key for new installs. This has been applied to make Umbraco more secure by default, but it's not been forced for upgrades. ## What's Changed ### 🙌 Notable Changes * Templates: Add optional Central Package Management support to UmbracoProject and UmbracoExtension templates by @NguyenThuyLan in umbraco/Umbraco-CMS#21641 * Service registration: Allow running Umbraco with different combinations of backoffice, website and delivery API (closes #21622) by @AndyButland in umbraco/Umbraco-CMS#21630 * Imaging Configuration: Auto-generate HMAC secret key for new installs by @AndyButland in umbraco/Umbraco-CMS#21976 * Migrations: Run unattended upgrades in background, add liveness/readiness health probes (closes #21987) by @AndyButland in umbraco/Umbraco-CMS#22020 ### 💥 Breaking Changes * Dependencies: Update MailKit to 4.15.1 by @AndyButland in umbraco/Umbraco-CMS#22028 ### 📦 Dependencies * Bump lodash from 4.17.21 to 4.17.23 in /tests/Umbraco.Tests.AcceptanceTest in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21519 * Bump the npm_and_yarn group across 2 directories with 2 updates by @dependabot[bot] in umbraco/Umbraco-CMS#21754 * Bump qs from 6.14.1 to 6.14.2 in /src/Umbraco.Web.UI.Client in the npm_and_yarn group across 1 directory by @dependabot[bot] in umbraco/Umbraco-CMS#21755 * Dependencies: Bumps @umbraco-ui/uui from 1.17.0 to 1.17.1 by @iOvergaard in umbraco/Umbraco-CMS#22029 * Dependencies: Updates @umbraco-ui/uui to 1.17.2 to fix multiple folder drag-and-drop failing (closes #21837) by @iOvergaard in umbraco/Umbraco-CMS#21886 * Backoffice: Update vite from 7.1.11 to 7.3.1 by @iOvergaard in umbraco/Umbraco-CMS#22065 * Dependencies: Update server-side dependencies to latest patch or minor releases by @AndyButland in umbraco/Umbraco-CMS#21860 ### 🚤 Performance * Performance: Implement key-based caching for data type and template repositories by @AndyButland in umbraco/Umbraco-CMS#21280 * Management API: Optimize collection view performance by eliminating N+1 patterns by @AndyButland in umbraco/Umbraco-CMS#21684 * Performance: Optimize handling of content type updates by @kjac in umbraco/Umbraco-CMS#21910 * Backoffice Performance: Add inflight request deduplication to item data request managers by @madsrasmussen in umbraco/Umbraco-CMS#21767 * URL and Alias Caches: Optimize for invariant documents by @AndyButland in umbraco/Umbraco-CMS#21558 * Custom Views: Prevent re-rendering Block Views and Properties by @rickbutterfield in umbraco/Umbraco-CMS#21186 * Core: Minimize await to a single JS cycle (refactor #21186) by @nielslyngsoe in umbraco/Umbraco-CMS#22074 * Auth: Skip /token refresh when access token is still valid by @iOvergaard in umbraco/Umbraco-CMS#22087 * Memory Management: Dispose `IDisposable` resources correctly in four internal classes by @AndyButland in umbraco/Umbraco-CMS#22014 * Redirect Tracking: Fix segment change detection and optimise descendant traversal (closes #22082) by @AndyButland in umbraco/Umbraco-CMS#22091 ### 🌈 Accessibility Improvements * Entity Actions: Adds a descriptive title to the first action so you know what it does by @iOvergaard in umbraco/Umbraco-CMS#21739 * Search field: Added aria-label and name to search input for accessibility (closes #21938) by @andreaslborg in umbraco/Umbraco-CMS#21962 * List view: Added labels entity bulk action buttons by @andreaslborg in umbraco/Umbraco-CMS#21964 * Accessibility: Add title attributes to buttons in block list entry and property editor UI by @manutdkid77 in umbraco/Umbraco-CMS#21842 * Accessibility: Add tooltips to block grid entry actions by @manutdkid77 in umbraco/Umbraco-CMS#21958 * Accessibility: Added `title` attribute for icon in content types by @TechPdo in umbraco/Umbraco-CMS#21956 ### 🚀 New Features ... (truncated) Commits viewable in [compare view](umbraco/Umbraco-CMS@release-17.2.2...release-17.3.0). </details> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alexander Seeliger <alexsee@users.noreply.github.com>
Prerequisites
Description
This PR aims at optimizing how content type updates are handled.
Essentially, content type changes can be divided into "destructive" and "constructive" categories - see this PR for details.
Claude has decided to call these changes "Structural changes" and "Non-structural changes", respectively. That's a less dramatic naming, so let's stick with that 😀
We can use these categories to determine the impact of content type updates.
For structural changes, we need to:
For non-structural changes, we only need to flush the in-memory cache for published content. The content cache in the database can be reused, and the Examine indexes remain unaffected.
As-is, all content type updates are treated the same, which means even changing a name or description triggers all of the above.
Additional changes
As part of this effort, I have also added a few additional optimizations to the content type change handling:
Test results
I've been testing this on a local database with ~10000 pages of the same content type.
More test results
On a local database with ~70000 pages of the same content type in 10 different languages, the results are very similar.
Interestingly, the bulk of time now seems to be spent rebuilding the published content cache in the database. This means we have another optimization opportunity by skipping the rebuild (or rebuilding on a background thread) and handling cache misses at runtime.
Co-authored by Claude 🤖