From 779242f289c02d87bd7ebd4cb2dbf6e49806f4fa Mon Sep 17 00:00:00 2001 From: Arkadiusz biel Date: Mon, 3 Jun 2024 13:20:44 +0100 Subject: [PATCH 1/2] chore: make indexing more resiliant --- .../Configuration/Models/IndexingSettings.cs | 4 ++ .../UmbracoBuilder.Examine.cs | 2 +- .../Examine/ContentIndexPopulator.cs | 45 +++++++++++++++++-- .../Examine/ExamineIndexRebuilder.cs | 27 ++++++++++- .../Examine/IIndexRebuildStatusManager.cs | 7 +++ .../Examine/IndexRebuildStatusManager.cs | 28 ++++++++++++ .../ExamineManagementController.cs | 30 ++++++------- src/Umbraco.Web.UI.New.Client | 1 + 8 files changed, 122 insertions(+), 22 deletions(-) create mode 100644 src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs create mode 100644 src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs create mode 160000 src/Umbraco.Web.UI.New.Client diff --git a/src/Umbraco.Core/Configuration/Models/IndexingSettings.cs b/src/Umbraco.Core/Configuration/Models/IndexingSettings.cs index ff3bebd9894a..b6dc8f1ad589 100644 --- a/src/Umbraco.Core/Configuration/Models/IndexingSettings.cs +++ b/src/Umbraco.Core/Configuration/Models/IndexingSettings.cs @@ -15,4 +15,8 @@ public class IndexingSettings /// [DefaultValue(StaticExplicitlyIndexEachNestedProperty)] public bool ExplicitlyIndexEachNestedProperty { get; set; } = StaticExplicitlyIndexEachNestedProperty; + /// + /// Defines how many items to index in a single page + /// + public int IndexingPageSize { get; set; } = 10000; } diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs index 4cd7df61a090..bac98ab6704c 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs @@ -57,7 +57,7 @@ public static IUmbracoBuilder AddExamine(this IUmbracoBuilder builder) builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddSingleton(); - + builder.Services.AddSingleton(); builder.Services.AddSingleton(); //TODO remove in Umbraco 15. Only the interface should be in the service provider builder.Services.AddUnique(); diff --git a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs index eb9e9f135fdd..19bdac7dbcfd 100644 --- a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs +++ b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs @@ -1,5 +1,9 @@ using Examine; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.Services; @@ -14,6 +18,7 @@ public class ContentIndexPopulator : IndexPopulator { private readonly IContentService _contentService; private readonly IValueSetBuilder _contentValueSetBuilder; + private IndexingSettings _indexingSettings; private readonly ILogger _logger; private readonly int? _parentId; @@ -28,6 +33,7 @@ public class ContentIndexPopulator : IndexPopulator /// /// Default constructor to lookup all content data /// + [Obsolete("Use the constructor with IOptionsMonitor")] public ContentIndexPopulator( ILogger logger, IContentService contentService, @@ -40,13 +46,14 @@ public ContentIndexPopulator( /// /// Optional constructor allowing specifying custom query parameters /// + [Obsolete("Use the constructor with IOptionsMonitor")] public ContentIndexPopulator( ILogger logger, bool publishedValuesOnly, int? parentId, IContentService contentService, IUmbracoDatabaseFactory umbracoDatabaseFactory, - IValueSetBuilder contentValueSetBuilder) + IValueSetBuilder contentValueSetBuilder) : this(logger, publishedValuesOnly, parentId, contentService, umbracoDatabaseFactory, contentValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService>()) { _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _umbracoDatabaseFactory = umbracoDatabaseFactory ?? throw new ArgumentNullException(nameof(umbracoDatabaseFactory)); @@ -55,7 +62,37 @@ public ContentIndexPopulator( _publishedValuesOnly = publishedValuesOnly; _parentId = parentId; } + public ContentIndexPopulator( + ILogger logger, + IContentService contentService, + IUmbracoDatabaseFactory umbracoDatabaseFactory, + IContentValueSetBuilder contentValueSetBuilder, + IOptionsMonitor indexingSettings) + : this(logger, false, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder,indexingSettings) + { + } + public ContentIndexPopulator( + ILogger logger, + bool publishedValuesOnly, + int? parentId, + IContentService contentService, + IUmbracoDatabaseFactory umbracoDatabaseFactory, + IValueSetBuilder contentValueSetBuilder, + IOptionsMonitor indexingSettings) + { + _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); + _umbracoDatabaseFactory = umbracoDatabaseFactory ?? throw new ArgumentNullException(nameof(umbracoDatabaseFactory)); + _contentValueSetBuilder = contentValueSetBuilder ?? throw new ArgumentNullException(nameof(contentValueSetBuilder)); + _indexingSettings = indexingSettings.CurrentValue; + indexingSettings.OnChange(change => + { + _indexingSettings = change; + }); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _publishedValuesOnly = publishedValuesOnly; + _parentId = parentId; + } private IQuery PublishedQuery => _publishedQuery ??= _umbracoDatabaseFactory.SqlContext.Query().Where(x => x.Published); @@ -75,7 +112,7 @@ protected override void PopulateIndexes(IReadOnlyList indexes) return; } - const int pageSize = 10000; + var pageIndex = 0; var contentParentId = -1; @@ -86,11 +123,11 @@ protected override void PopulateIndexes(IReadOnlyList indexes) if (_publishedValuesOnly) { - IndexPublishedContent(contentParentId, pageIndex, pageSize, indexes); + IndexPublishedContent(contentParentId, pageIndex, _indexingSettings.IndexingPageSize, indexes); } else { - IndexAllContent(contentParentId, pageIndex, pageSize, indexes); + IndexAllContent(contentParentId, pageIndex, _indexingSettings.IndexingPageSize, indexes); } } diff --git a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs index 5fe98dca0bb3..8169c86d0df0 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs @@ -2,8 +2,10 @@ // See LICENSE for more details. using Examine; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.HostedServices; @@ -16,6 +18,7 @@ public class ExamineIndexRebuilder : IIndexRebuilder private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly IExamineManager _examineManager; private readonly ILogger _logger; + private readonly IIndexRebuildStatusManager _indexRebuildStatusManager; private readonly IMainDom _mainDom; private readonly IEnumerable _populators; private readonly object _rebuildLocker = new(); @@ -24,17 +27,29 @@ public class ExamineIndexRebuilder : IIndexRebuilder /// /// Initializes a new instance of the class. /// + [Obsolete("Use constructor with IIndexRebuildStatusManager. This is scheduled for removal in Umbraco 15.")] public ExamineIndexRebuilder( IMainDom mainDom, IRuntimeState runtimeState, ILogger logger, IExamineManager examineManager, IEnumerable populators, + IBackgroundTaskQueue backgroundTaskQueue) : this(mainDom, runtimeState, logger, StaticServiceProvider.Instance.GetRequiredService(), examineManager, populators, backgroundTaskQueue) + { + } + public ExamineIndexRebuilder( + IMainDom mainDom, + IRuntimeState runtimeState, + ILogger logger, + IIndexRebuildStatusManager indexRebuildStatusManager, + IExamineManager examineManager, + IEnumerable populators, IBackgroundTaskQueue backgroundTaskQueue) { _mainDom = mainDom; _runtimeState = runtimeState; _logger = logger; + _indexRebuildStatusManager = indexRebuildStatusManager; _examineManager = examineManager; _populators = populators; _backgroundTaskQueue = backgroundTaskQueue; @@ -147,7 +162,7 @@ private void RebuildIndex(string indexName, TimeSpan delay, CancellationToken ca { throw new InvalidOperationException($"No index found with name {indexName}"); } - + _indexRebuildStatusManager.SetRebuildingIndexStatus([indexName], true); index.CreateIndex(); // clear the index foreach (IIndexPopulator populator in _populators) { @@ -158,6 +173,7 @@ private void RebuildIndex(string indexName, TimeSpan delay, CancellationToken ca populator.Populate(index); } + _indexRebuildStatusManager.SetRebuildingIndexStatus([indexName], false); } } finally @@ -175,6 +191,7 @@ private void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan delay, CancellationT { Thread.Sleep(delay); } + IEnumerable? rebuildedIndex = null; try { @@ -190,7 +207,8 @@ private void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan delay, CancellationT ? _examineManager.Indexes.Where(x => !x.IndexExists() || (x is IIndexStats stats && stats.GetDocumentCount() == 0)) : _examineManager.Indexes).ToArray(); - + rebuildedIndex = indexes.Select(x => x.Name); + _indexRebuildStatusManager.SetRebuildingIndexStatus(rebuildedIndex, true); if (indexes.Length == 0) { return; @@ -218,10 +236,15 @@ private void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan delay, CancellationT _logger.LogError(e, "Index populating failed for populator {Populator}", populator.GetType()); } } + } } finally { + if (rebuildedIndex != null && rebuildedIndex.Any()) + { + _indexRebuildStatusManager.SetRebuildingIndexStatus(rebuildedIndex, false); + } if (Monitor.IsEntered(_rebuildLocker)) { Monitor.Exit(_rebuildLocker); diff --git a/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs b/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs new file mode 100644 index 000000000000..10c70563d0ef --- /dev/null +++ b/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Cms.Infrastructure.Examine; + +public interface IIndexRebuildStatusManager +{ + void SetRebuildingIndexStatus(IEnumerable indexes, bool b); + bool GetRebuildingIndexStatus(string index); +} diff --git a/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs b/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs new file mode 100644 index 000000000000..2218b5f2afce --- /dev/null +++ b/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs @@ -0,0 +1,28 @@ +using Examine; + +namespace Umbraco.Cms.Infrastructure.Examine; + +/// +/// +/// +public class IndexRebuildStatusManager : IIndexRebuildStatusManager +{ + IDictionary _rebuildingStatus = new Dictionary(); + public IndexRebuildStatusManager(IExamineManager examineManager) + { + foreach (var index in examineManager.Indexes) + { + _rebuildingStatus.Add(index.Name, false); + } + } + + public void SetRebuildingIndexStatus(IEnumerable indexes, bool isRebuilding) + { + foreach (var index in indexes) + { + _rebuildingStatus[index] = isRebuilding; + } + } + + public bool GetRebuildingIndexStatus(string index) => _rebuildingStatus.TryGetValue(index, out var isRebuilding) && isRebuilding; +} diff --git a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs index 21cb7fdcd942..e8c79c63aa9d 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs @@ -3,9 +3,11 @@ using Lucene.Net.QueryParsers.Classic; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Infrastructure.Examine; using Umbraco.Cms.Web.Common.Attributes; @@ -22,23 +24,32 @@ public class ExamineManagementController : UmbracoAuthorizedJsonController private readonly IExamineManager _examineManager; private readonly IIndexDiagnosticsFactory _indexDiagnosticsFactory; private readonly IIndexRebuilder _indexRebuilder; + private readonly IIndexRebuildStatusManager _rebuildStatusManager; private readonly ILogger _logger; private readonly IAppPolicyCache _runtimeCache; - + [Obsolete("Use the ctor with IOptionsMonitor>")] public ExamineManagementController( IExamineManager examineManager, ILogger logger, IIndexDiagnosticsFactory indexDiagnosticsFactory, AppCaches appCaches, - IIndexRebuilder indexRebuilder) + IIndexRebuilder indexRebuilder) : this(examineManager, logger, indexDiagnosticsFactory, appCaches, indexRebuilder, StaticServiceProvider.Instance.GetRequiredService()) + { + } + public ExamineManagementController( + IExamineManager examineManager, + ILogger logger, + IIndexDiagnosticsFactory indexDiagnosticsFactory, + AppCaches appCaches, + IIndexRebuilder indexRebuilder, IIndexRebuildStatusManager rebuildStatusManager) { _examineManager = examineManager; _logger = logger; _indexDiagnosticsFactory = indexDiagnosticsFactory; _runtimeCache = appCaches.RuntimeCache; _indexRebuilder = indexRebuilder; + _rebuildStatusManager = rebuildStatusManager; } - /// /// Get the details for indexers /// @@ -129,11 +140,8 @@ public ActionResult GetSearchResults(string searcherName, string? return validate; } - var cacheKey = "temp_indexing_op_" + indexName; - var found = _runtimeCache.Get(cacheKey); - //if its still there then it's not done - return found != null + return _rebuildStatusManager.GetRebuildingIndexStatus(indexName) ? null : CreateModel(index!); } @@ -167,12 +175,7 @@ public IActionResult PostRebuildIndex(string indexName) try { - var cacheKey = "temp_indexing_op_" + index.Name; - //put temp val in cache which is used as a rudimentary way to know when the indexing is done - _runtimeCache.Insert(cacheKey, () => "tempValue", TimeSpan.FromMinutes(5)); - _indexRebuilder.RebuildIndex(indexName); - return new OkResult(); } catch (Exception ex) @@ -307,8 +310,5 @@ private void Indexer_IndexOperationComplete(object? sender, EventArgs e) } _logger.LogInformation("Rebuilding index '{indexerName}' done.", indexer?.Name); - - var cacheKey = "temp_indexing_op_" + indexer?.Name; - _runtimeCache.Clear(cacheKey); } } diff --git a/src/Umbraco.Web.UI.New.Client b/src/Umbraco.Web.UI.New.Client new file mode 160000 index 000000000000..c48ede4dee5c --- /dev/null +++ b/src/Umbraco.Web.UI.New.Client @@ -0,0 +1 @@ +Subproject commit c48ede4dee5c9f1fd7986042edb67ddee5258054 From ad5ccefeef7dc35d2ef93c587b0140bd50275d1c Mon Sep 17 00:00:00 2001 From: Arkadiusz Biel - bielu Date: Sat, 15 Jun 2024 19:16:48 +0100 Subject: [PATCH 2/2] POC: add populator information to reindex model --- .../Examine/ContentIndexPopulator.cs | 21 ++++- .../Examine/ExamineIndexRebuilder.cs | 3 +- .../Examine/IIndexRebuildStatusManager.cs | 29 ++++++- .../Examine/IndexRebuildStatusManager.cs | 76 +++++++++++++++++-- .../ExamineManagementController.cs | 14 +++- 5 files changed, 125 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs index 19bdac7dbcfd..6b97fe7595df 100644 --- a/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs +++ b/src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; using Examine; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -18,6 +19,7 @@ public class ContentIndexPopulator : IndexPopulator { private readonly IContentService _contentService; private readonly IValueSetBuilder _contentValueSetBuilder; + private readonly IIndexRebuildStatusManager _indexRebuildStatusManager; private IndexingSettings _indexingSettings; private readonly ILogger _logger; private readonly int? _parentId; @@ -78,11 +80,13 @@ public ContentIndexPopulator( IContentService contentService, IUmbracoDatabaseFactory umbracoDatabaseFactory, IValueSetBuilder contentValueSetBuilder, - IOptionsMonitor indexingSettings) + IOptionsMonitor indexingSettings, + IIndexRebuildStatusManager indexRebuildStatusManager) { _contentService = contentService ?? throw new ArgumentNullException(nameof(contentService)); _umbracoDatabaseFactory = umbracoDatabaseFactory ?? throw new ArgumentNullException(nameof(umbracoDatabaseFactory)); _contentValueSetBuilder = contentValueSetBuilder ?? throw new ArgumentNullException(nameof(contentValueSetBuilder)); + _indexRebuildStatusManager = indexRebuildStatusManager; _indexingSettings = indexingSettings.CurrentValue; indexingSettings.OnChange(change => { @@ -134,22 +138,33 @@ protected override void PopulateIndexes(IReadOnlyList indexes) protected void IndexAllContent(int contentParentId, int pageIndex, int pageSize, IReadOnlyList indexes) { IContent[] content; - + var totalBatches = 0; do { - content = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out _).ToArray(); + content = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out var total).ToArray(); + if (totalBatches == 0) + { + totalBatches = (int)Math.Ceiling((decimal)total / pageSize); + } var valueSets = _contentValueSetBuilder.GetValueSets(content).ToArray(); // ReSharper disable once PossibleMultipleEnumeration foreach (IIndex index in indexes) { + _indexRebuildStatusManager.UpdatePopulatorStatus(index.Name, GetType().Name, true, pageIndex, totalBatches); + index.IndexItems(valueSets); } pageIndex++; } while (content.Length == pageSize); + + foreach (IIndex index in indexes) + { + _indexRebuildStatusManager.UpdatePopulatorStatus(index.Name, GetType().Name, false, totalBatches, totalBatches); + } } protected void IndexPublishedContent(int contentParentId, int pageIndex, int pageSize, IReadOnlyList indexes) diff --git a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs index 8169c86d0df0..ac83462fa814 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs @@ -162,7 +162,7 @@ private void RebuildIndex(string indexName, TimeSpan delay, CancellationToken ca { throw new InvalidOperationException($"No index found with name {indexName}"); } - _indexRebuildStatusManager.SetRebuildingIndexStatus([indexName], true); + _indexRebuildStatusManager.SetReindexStatus(index, _populators.Where(x=>x.IsRegistered(index))); index.CreateIndex(); // clear the index foreach (IIndexPopulator populator in _populators) { @@ -173,7 +173,6 @@ private void RebuildIndex(string indexName, TimeSpan delay, CancellationToken ca populator.Populate(index); } - _indexRebuildStatusManager.SetRebuildingIndexStatus([indexName], false); } } finally diff --git a/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs b/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs index 10c70563d0ef..2d0b45b151ae 100644 --- a/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs +++ b/src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs @@ -1,7 +1,30 @@ -namespace Umbraco.Cms.Infrastructure.Examine; +using Examine; + +namespace Umbraco.Cms.Infrastructure.Examine; public interface IIndexRebuildStatusManager { - void SetRebuildingIndexStatus(IEnumerable indexes, bool b); - bool GetRebuildingIndexStatus(string index); + IndexStatus? GetRebuildingIndexStatus(string index); + void SetReindexStatus(IIndex index, IEnumerable where); + + public void UpdatePopulatorStatus(string index, string populator, bool isRunning, int currentBatch, int totalBatches); +} + +public class IndexStatus +{ + public bool IsRebuilding { get; set; } + public IEnumerable? PopulatorStatuses { get; set; } +} + +public class PopulatorStatus +{ + public PopulatorStatus(string name) + { + Name = name; + } + + public string Name { get; set; } + public bool IsRunning { get; set; } + public int CurrentBatch { get; set; } + public int TotalBatches { get; set; } } diff --git a/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs b/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs index 2218b5f2afce..322283b557d4 100644 --- a/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs +++ b/src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs @@ -7,22 +7,86 @@ namespace Umbraco.Cms.Infrastructure.Examine; /// public class IndexRebuildStatusManager : IIndexRebuildStatusManager { - IDictionary _rebuildingStatus = new Dictionary(); + private readonly IExamineManager _examineManager; + IDictionary _rebuildingStatus = new Dictionary(); + public IndexRebuildStatusManager(IExamineManager examineManager) { + _examineManager = examineManager; foreach (var index in examineManager.Indexes) { - _rebuildingStatus.Add(index.Name, false); + _rebuildingStatus.Add(index.Name, new IndexStatus()); } } - public void SetRebuildingIndexStatus(IEnumerable indexes, bool isRebuilding) + public IndexStatus? GetRebuildingIndexStatus(string index) => + _rebuildingStatus.TryGetValue(index, out var status) ? status : null; + + public void SetReindexStatus(IIndex index, IEnumerable where) { - foreach (var index in indexes) + if (!_rebuildingStatus.TryGetValue(index.Name, out var status)) { - _rebuildingStatus[index] = isRebuilding; + status = new IndexStatus(); + _rebuildingStatus.Add(index.Name, status); } + + status.IsRebuilding = true; + status.PopulatorStatuses = where.Select(x => new PopulatorStatus(x.GetType().Name)); } - public bool GetRebuildingIndexStatus(string index) => _rebuildingStatus.TryGetValue(index, out var isRebuilding) && isRebuilding; + public void UpdatePopulatorStatus( + string index, + string populator, + bool isRunning, + int currentBatch, + int totalBatches) + { + var examineIndex = _examineManager.GetIndex(index); + + if (_rebuildingStatus.TryGetValue(index, out var status)) + { + var populatorStatus = status?.PopulatorStatuses?.FirstOrDefault(x => x.Name == populator); + if (populatorStatus != null) + { + populatorStatus.IsRunning = isRunning; + populatorStatus.CurrentBatch = currentBatch; + populatorStatus.TotalBatches = totalBatches; + } + + examineIndex.IndexItems( + [ + new ValueSet( + populator, + "populator", + new Dictionary() + { + { "isRunning", isRunning }, + { "currentBatch", currentBatch }, + { "totalBatches", totalBatches } + }) + ]); + return; + } + var currentStatus= new IndexStatus(); + _rebuildingStatus.Add(index,currentStatus); + var newPopulatorStatus = new PopulatorStatus(populator) + { + IsRunning = isRunning, + CurrentBatch = currentBatch, + TotalBatches = totalBatches + }; + currentStatus.PopulatorStatuses = new List { newPopulatorStatus }; + examineIndex.IndexItems( + [ + new ValueSet( + populator, + "populator", + new Dictionary() + { + { "isRunning", isRunning }, + { "currentBatch", currentBatch }, + { "totalBatches", totalBatches } + }) + ]); + } } diff --git a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs index e8c79c63aa9d..aea281e42390 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs @@ -140,9 +140,10 @@ public ActionResult GetSearchResults(string searcherName, string? return validate; } + var status = _rebuildStatusManager.GetRebuildingIndexStatus(indexName); //if its still there then it's not done - return _rebuildStatusManager.GetRebuildingIndexStatus(indexName) - ? null + return status?.IsRebuilding == true + ? CreateModel(index!, status) : CreateModel(index!); } @@ -191,10 +192,11 @@ public IActionResult PostRebuildIndex(string indexName) } } - private ExamineIndexModel CreateModel(IIndex index) + private ExamineIndexModel CreateModel(IIndex index, IndexStatus? status = null) { var indexName = index.Name; IIndexDiagnostics indexDiag = _indexDiagnosticsFactory.Create(index); + Attempt isHealth = indexDiag.IsHealthy(); var healthResult = isHealth.Result; @@ -230,7 +232,11 @@ private ExamineIndexModel CreateModel(IIndex index) ["DocumentCount"] = documentCount, ["FieldCount"] = fieldCount }; - + if(status is not null) + { + properties["IsRebuilding"] = status.IsRebuilding; + properties["PopulatorStatuses"] = status.PopulatorStatuses; + } foreach (KeyValuePair p in indexDiag.Metadata) { properties[p.Key] = p.Value;