This follows the release of a beta two weeks ago. Since then, we've spent the time looking into reported issues, bringing in some additional bug fixes, and generally polishing to get to the point of releasing the RC today. That'll continue over the next period, but we'll be limiting change now to only the resolution of issues found or reported in regression testing.
Along with the beta release a fortnight ago came an introductory blog post, which, if you haven't read it already, I'd recommend doing so before proceeding with this one. It sets the scene a little more broadly for those following Umbraco's Long-term Support (LTS) release cycle. Umbraco 17 will be the next LTS, so for those of you looking to move up from Umbraco 13, there's a fair bit to review and consider when planning your upgrade.
With this blog post, I want to dive into more detail on those aspects of Umbraco 17 that are new, even for those who have kept up with the short-term support (STS) releases and are already running on Umbraco 16.
Dependencies and Breaking Changes
However, let's first address the usual topics related to a major Umbraco release. Umbraco 17 runs on .NET 10, the latest release of .NET and available at the time of publication as a release candidate itself. You can download the latest version from here, and you will need to do that in the environment where you want to install Umbraco 17.
There are some breaking changes involved in the new release, which you can find detailed here. It's worth particularly calling out the changes related to Microsoft's decision to deprecate Razor runtime compilation. In order to work toward better support of the replacement for this - hot reload - in the future, we've broken out the components necessary for InMemoryAuto models builder and razor runtime compilation into their own package. So you'll need to make sure to reference this if installing or upgrading and wanting to retain these features.
Other documentation updates as they relate to new features are linked along with the discussion on the feature below.
We've taken the opportunity to upgrade all Umbraco dependencies to their latest compatible versions, including major version updates to the NPoco, OpenIddict, Serilog and Swashbuckle libraries. Further details are available in the breaking changes documentation.
Load Balancing the Backoffice
A project over the last six months has been to solve what's been a long-term question of why we can't load balance the backoffice. Load balancing of Umbraco for the front-end website has been possible for a long time, but it's always come with this caveat of only having a single server for the backoffice.
We wanted to remove that. Partly, as we know, Umbraco is increasingly being used for larger editorial teams, where providing resilience and resources only via scaling up a single server is too limited. We also wanted to simplify the process of load balancing Umbraco, such that it's possible to more straightforwardly scale the whole Umbraco application, without the complication of splitting into backoffice and front-end web servers.
The first part of the project was to analyse and find the areas where we were currently limited to a single server setup, which led to the following set of concerns we had to address.
Repository Caches
Also known as "isolated caches", these are held within Umbraco to improve performance at the data layer. Requests to retrieve a given entity even outside of the front-end caches don't necessarily always hit the database. Rather, we maintain repository-level caches that are invalidated only when the entity is updated.
This presented a problem for load balancing the backoffice, as we could easily have a scenario where, after one server receives a request to save a content item, a different server receives the request to publish it. The publishing server would have an outdated version of the item in its repository cache because the refreshers that invalidate these caches haven't run yet.
To address this issue, we have introduced a cache version mechanism that allows servers to detect when their isolated caches are out of sync. When an out-of-sync cache is detected, we automatically roll the cache forward to bring it up to date.
As these changes are only relevant for sites with load-balanced backoffice environments, we've made this an opt-in feature.
Background Tasks
Umbraco has several periodic background jobs that can be divided into "per-server" and "distributed" tasks. The former we want to run on every server in a load balanced setup, but the latter should only run once on each occasion for the entire cluster.
The firing of webhooks is an example of a distributed task - if that were to run on every load balanced server we'd at best have unnecessary processing and at worst cause issues downstream by sending duplicate messages.
We've moved the tracking of distributed jobs now to the database, with each server querying and this to pick up and run jobs.
Long Running Operations
Long-running operations that use a "submit and poll" technique were bound to a single server, as the status of the ongoing task was held in memory. We've addressed and improved this by introducing a dedicated service for these operations, and storing the state of them in the database.
Removal of Files on Disk
As well as state stored in memory, another thing to avoid with load balanced setups is using files on local server disks to persist information. Umbraco had one of these we needed to address, a small and innocuous file used for tracking cache and search index status, which in turn controls whether Umbraco will boot hot or cold. Again a database backed service was introduced for this.