Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/Umbraco.Core/Services/DocumentUrlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ namespace Umbraco.Cms.Core.Services;
/// </summary>
public class DocumentUrlService : IDocumentUrlService
{
private const string RebuildKey = "UmbracoUrlGeneration";
/// <summary>
/// Represents the key used to identify the URL generation rebuild operation.
/// </summary>
public const string RebuildKey = "UmbracoUrlGeneration";

private readonly ILogger<DocumentUrlService> _logger;
private readonly IDocumentUrlRepository _documentUrlRepository;
Expand All @@ -46,6 +49,9 @@ public class DocumentUrlService : IDocumentUrlService
private readonly ConcurrentDictionary<string, int> _cultureToLanguageIdMap = new();
private bool _isInitialized;

/// <inheritdoc/>
public bool IsInitialized => _isInitialized;

/// <summary>
/// Struct-based cache key for memory-efficient URL segment caching.
/// Uses LanguageId instead of culture string to reduce memory footprint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public async Task HandleAsync(UmbracoApplicationStartingNotification notificatio
return;
}

// Skip if already initialized (e.g., by ContentCacheRefresher after migration)
if (_documentUrlService.IsInitialized)
{
return;
}

await _documentUrlService.InitAsync(
_runtimeState.Level <= RuntimeLevel.Install,
cancellationToken);
Expand Down
6 changes: 6 additions & 0 deletions src/Umbraco.Core/Services/IDocumentUrlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ namespace Umbraco.Cms.Core.Services;
/// </summary>
public interface IDocumentUrlService
{
/// <summary>
/// Gets a value indicating whether the service has been initialized.
/// </summary>
// TODO (V18): Remove the default implementation.
bool IsInitialized => false;

/// <summary>
/// Initializes the service and ensure the content in the database is correct with the current configuration.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,38 @@
using Umbraco.Cms.Core.Services;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_15_0_0;

[Obsolete("Remove in Umbraco 18.")]
public class RebuildDocumentUrls : MigrationBase
{
private readonly IDocumentUrlService _documentUrlService;
private readonly IKeyValueService _keyValueService;

public RebuildDocumentUrls(IMigrationContext context, IDocumentUrlService documentUrlService)
: base(context) =>
_documentUrlService = documentUrlService;
: this(
context,
documentUrlService,
StaticServiceProvider.Instance.GetRequiredService<IKeyValueService>())
{
}

protected override void Migrate()
=> _documentUrlService.InitAsync(false, CancellationToken.None).GetAwaiter().GetResult();
public RebuildDocumentUrls(IMigrationContext context, IDocumentUrlService documentUrlService, IKeyValueService keyValueService)
: base(context)
{
// The documentUrlService parameter is kept for backward compatibility and to maintain
// constructor signature compatibility with earlier versions/DI registrations. It is not
// required by this migration, which only needs access to IKeyValueService.
_ = documentUrlService;
_keyValueService = keyValueService;
}

/// <inheritdoc/>
protected override void Migrate() =>

// Clear any existing key to force rebuild on first normal startup.
// This ensures URL generation runs when all services are fully initialized,
// rather than during migration when variant content data may not be accessible.
// See: https://github.com/umbraco/Umbraco-CMS/issues/21337
_keyValueService.SetValue(DocumentUrlService.RebuildKey, string.Empty);
}
Loading