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

POC: Feat/make indexing more resiliant #16546

Open
wants to merge 2 commits into
base: v13/dev
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions src/Umbraco.Core/Configuration/Models/IndexingSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ public class IndexingSettings
/// </summary>
[DefaultValue(StaticExplicitlyIndexEachNestedProperty)]
public bool ExplicitlyIndexEachNestedProperty { get; set; } = StaticExplicitlyIndexEachNestedProperty;
/// <summary>
/// Defines how many items to index in a single page
/// </summary>
public int IndexingPageSize { get; set; } = 10000;
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static IUmbracoBuilder AddExamine(this IUmbracoBuilder builder)
builder.Services.AddUnique<IDeliveryApiContentIndexFieldDefinitionBuilder, DeliveryApiContentIndexFieldDefinitionBuilder>();
builder.Services.AddUnique<IDeliveryApiContentIndexHelper, DeliveryApiContentIndexHelper>();
builder.Services.AddSingleton<IDeliveryApiIndexingHandler, DeliveryApiIndexingHandler>();

builder.Services.AddSingleton<IIndexRebuildStatusManager, IndexRebuildStatusManager>();
builder.Services.AddSingleton<ExamineIndexRebuilder>(); //TODO remove in Umbraco 15. Only the interface should be in the service provider

builder.Services.AddUnique<IDeliveryApiCompositeIdHandler, DeliveryApiCompositeIdHandler>();
Expand Down
64 changes: 58 additions & 6 deletions src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using System.Text.RegularExpressions;

Check warning on line 1 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

❌ New issue: Missing Arguments Abstractions

The average number of function arguments in this module is 4.13 across 8 functions. The average arguments threshold is 4.00. The functions in this file have too many arguments, indicating a lack of encapsulation or too many responsibilities in the same functions. Avoid adding more.
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;
Expand All @@ -14,6 +19,8 @@
{
private readonly IContentService _contentService;
private readonly IValueSetBuilder<IContent> _contentValueSetBuilder;
private readonly IIndexRebuildStatusManager _indexRebuildStatusManager;
private IndexingSettings _indexingSettings;
private readonly ILogger<ContentIndexPopulator> _logger;
private readonly int? _parentId;

Expand All @@ -28,6 +35,7 @@
/// <summary>
/// Default constructor to lookup all content data
/// </summary>
[Obsolete("Use the constructor with IOptionsMonitor<IndexingSettings>")]
public ContentIndexPopulator(
ILogger<ContentIndexPopulator> logger,
IContentService contentService,
Expand All @@ -40,13 +48,14 @@
/// <summary>
/// Optional constructor allowing specifying custom query parameters
/// </summary>
[Obsolete("Use the constructor with IOptionsMonitor<IndexingSettings>")]
public ContentIndexPopulator(
ILogger<ContentIndexPopulator> logger,
bool publishedValuesOnly,
int? parentId,
IContentService contentService,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IValueSetBuilder<IContent> contentValueSetBuilder)
IValueSetBuilder<IContent> contentValueSetBuilder) : this(logger, publishedValuesOnly, parentId, contentService, umbracoDatabaseFactory, contentValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())

Check failure on line 58 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 58 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 58 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+ (Build Build Umbraco CMS)

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs#L58

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs(58,62): Error CS7036: There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 58 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs#L58

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs(58,62): Error CS7036: There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'
{
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
_umbracoDatabaseFactory = umbracoDatabaseFactory ?? throw new ArgumentNullException(nameof(umbracoDatabaseFactory));
Expand All @@ -55,7 +64,39 @@
_publishedValuesOnly = publishedValuesOnly;
_parentId = parentId;
}
public ContentIndexPopulator(
ILogger<ContentIndexPopulator> logger,
IContentService contentService,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IContentValueSetBuilder contentValueSetBuilder,
IOptionsMonitor<IndexingSettings> indexingSettings)
: this(logger, false, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder,indexingSettings)

Check failure on line 73 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 73 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 73 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+ (Build Build Umbraco CMS)

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs#L73

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs(73,11): Error CS7036: There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'

Check failure on line 73 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs#L73

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs(73,11): Error CS7036: There is no argument given that corresponds to the required parameter 'indexRebuildStatusManager' of 'ContentIndexPopulator.ContentIndexPopulator(ILogger<ContentIndexPopulator>, bool, int?, IContentService, IUmbracoDatabaseFactory, IValueSetBuilder<IContent>, IOptionsMonitor<IndexingSettings>, IIndexRebuildStatusManager)'
{
}
public ContentIndexPopulator(
ILogger<ContentIndexPopulator> logger,
bool publishedValuesOnly,
int? parentId,
IContentService contentService,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IValueSetBuilder<IContent> contentValueSetBuilder,
IOptionsMonitor<IndexingSettings> 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 =>
{
_indexingSettings = change;
});
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_publishedValuesOnly = publishedValuesOnly;
_parentId = parentId;

}

Check notice on line 99 in src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

ℹ New issue: Constructor Over-Injection

ContentIndexPopulator has 8 arguments, threshold = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.
private IQuery<IContent> PublishedQuery => _publishedQuery ??=
_umbracoDatabaseFactory.SqlContext.Query<IContent>().Where(x => x.Published);

Expand All @@ -75,7 +116,7 @@
return;
}

const int pageSize = 10000;

var pageIndex = 0;

var contentParentId = -1;
Expand All @@ -86,33 +127,44 @@

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);
}
}

protected void IndexAllContent(int contentParentId, int pageIndex, int pageSize, IReadOnlyList<IIndex> 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<IIndex> indexes)
Expand Down
26 changes: 24 additions & 2 deletions src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// Copyright (c) Umbraco.

Check notice on line 1 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 4.71 to 4.50, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
// 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;
Expand All @@ -16,6 +18,7 @@
private readonly IBackgroundTaskQueue _backgroundTaskQueue;
private readonly IExamineManager _examineManager;
private readonly ILogger<ExamineIndexRebuilder> _logger;
private readonly IIndexRebuildStatusManager _indexRebuildStatusManager;
private readonly IMainDom _mainDom;
private readonly IEnumerable<IIndexPopulator> _populators;
private readonly object _rebuildLocker = new();
Expand All @@ -24,17 +27,29 @@
/// <summary>
/// Initializes a new instance of the <see cref="ExamineIndexRebuilder" /> class.
/// </summary>
[Obsolete("Use constructor with IIndexRebuildStatusManager. This is scheduled for removal in Umbraco 15.")]
public ExamineIndexRebuilder(
IMainDom mainDom,
IRuntimeState runtimeState,
ILogger<ExamineIndexRebuilder> logger,
IExamineManager examineManager,
IEnumerable<IIndexPopulator> populators,
IBackgroundTaskQueue backgroundTaskQueue) : this(mainDom, runtimeState, logger, StaticServiceProvider.Instance.GetRequiredService<IIndexRebuildStatusManager>(), examineManager, populators, backgroundTaskQueue)
{
}
public ExamineIndexRebuilder(
IMainDom mainDom,
IRuntimeState runtimeState,
ILogger<ExamineIndexRebuilder> logger,
IIndexRebuildStatusManager indexRebuildStatusManager,
IExamineManager examineManager,
IEnumerable<IIndexPopulator> populators,
IBackgroundTaskQueue backgroundTaskQueue)
{
_mainDom = mainDom;
_runtimeState = runtimeState;
_logger = logger;
_indexRebuildStatusManager = indexRebuildStatusManager;

Check notice on line 52 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

ℹ New issue: Constructor Over-Injection

ExamineIndexRebuilder has 7 arguments, threshold = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.
_examineManager = examineManager;
_populators = populators;
_backgroundTaskQueue = backgroundTaskQueue;
Expand Down Expand Up @@ -147,7 +162,7 @@
{
throw new InvalidOperationException($"No index found with name {indexName}");
}

_indexRebuildStatusManager.SetReindexStatus(index, _populators.Where(x=>x.IsRegistered(index)));
index.CreateIndex(); // clear the index
foreach (IIndexPopulator populator in _populators)
{
Expand Down Expand Up @@ -175,22 +190,24 @@
{
Thread.Sleep(delay);
}
IEnumerable<string>? rebuildedIndex = null;

try
{
if (!Monitor.TryEnter(_rebuildLocker))
{
_logger.LogWarning(
$"Call was made to {nameof(RebuildIndexes)} but the task runner for rebuilding is already running");
}
else
{
// If an index exists but it has zero docs we'll consider it empty and rebuild
IIndex[] indexes = (onlyEmptyIndexes
? _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);

Check failure on line 210 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 210 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 210 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+ (Build Build Umbraco CMS)

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs#L210

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs(210,44): Error CS1061: 'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 210 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs#L210

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs(210,44): Error CS1061: 'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)
if (indexes.Length == 0)
{
return;
Expand Down Expand Up @@ -218,10 +235,15 @@
_logger.LogError(e, "Index populating failed for populator {Populator}", populator.GetType());
}
}

}
}
finally
{
if (rebuildedIndex != null && rebuildedIndex.Any())
{
_indexRebuildStatusManager.SetRebuildingIndexStatus(rebuildedIndex, false);

Check failure on line 245 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 245 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View workflow job for this annotation

GitHub Actions / CodeQL-Build

'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 245 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+ (Build Build Umbraco CMS)

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs#L245

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs(245,44): Error CS1061: 'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 245 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

Azure Pipelines / Umbraco CMS 9+

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs#L245

src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs(245,44): Error CS1061: 'IIndexRebuildStatusManager' does not contain a definition for 'SetRebuildingIndexStatus' and no accessible extension method 'SetRebuildingIndexStatus' accepting a first argument of type 'IIndexRebuildStatusManager' could be found (are you missing a using directive or an assembly reference?)
}

Check warning on line 246 in src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

❌ Getting worse: Complex Method

RebuildIndexes increases in cyclomatic complexity from 12 to 14, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.
if (Monitor.IsEntered(_rebuildLocker))
{
Monitor.Exit(_rebuildLocker);
Expand Down
30 changes: 30 additions & 0 deletions src/Umbraco.Infrastructure/Examine/IIndexRebuildStatusManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Examine;

namespace Umbraco.Cms.Infrastructure.Examine;

public interface IIndexRebuildStatusManager
{
IndexStatus? GetRebuildingIndexStatus(string index);
void SetReindexStatus(IIndex index, IEnumerable<IIndexPopulator> where);

public void UpdatePopulatorStatus(string index, string populator, bool isRunning, int currentBatch, int totalBatches);
}

public class IndexStatus
{
public bool IsRebuilding { get; set; }
public IEnumerable<PopulatorStatus>? 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; }
}
92 changes: 92 additions & 0 deletions src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using Examine;

namespace Umbraco.Cms.Infrastructure.Examine;

/// <summary>
///
/// </summary>
public class IndexRebuildStatusManager : IIndexRebuildStatusManager
Copy link
Contributor

Choose a reason for hiding this comment

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

My recommended approach would be to do this: Shazwazza/Examine#372 (comment)

The only real way to know if the indexing is done in a resilient way would be to have an actual document in the index certifying that rebuilding is successful instead of relying on in-memory cache which is problematic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Shazwazza I am not 100% convinced about usage of additional index, as we both know less indexes is actually better with lucene. I am thinking maybe we should use additonal sql table, as it will be eqally resiliant as using index, but it will not require us to create index, what you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

@bielu Sorry, I probably wasn't clear in my suggestion. We don't want to use an extra index to store any data, we can just use a marker document within the index. For example:

  • Rebuilding an index deletes all data
  • The index is populated with the normal data
  • When the IndexPopulator is done populating the index, it then writes a special marker document signaling that the populator is done. Perhaps this document has a field like __Populated: y

Then the rebuild checker, just checks if the document count for __Populated: y == 1

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Shazwazza that's make sense now! We can also extend it to check what populator are registered to show how many of them is done! I will make update to this pr

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Shazwazza i started changing implementation of this service to use examine underhood, can you have quick look and check if that is what you had in mind?
as in this way now we can also repeat failed batches (but i think I will need play around little more)

{
private readonly IExamineManager _examineManager;
IDictionary<string, IndexStatus> _rebuildingStatus = new Dictionary<string, IndexStatus>();

public IndexRebuildStatusManager(IExamineManager examineManager)
{
_examineManager = examineManager;
foreach (var index in examineManager.Indexes)
{
_rebuildingStatus.Add(index.Name, new IndexStatus());
}
}

public IndexStatus? GetRebuildingIndexStatus(string index) =>
_rebuildingStatus.TryGetValue(index, out var status) ? status : null;

public void SetReindexStatus(IIndex index, IEnumerable<IIndexPopulator> where)
{
if (!_rebuildingStatus.TryGetValue(index.Name, out var status))
{
status = new IndexStatus();
_rebuildingStatus.Add(index.Name, status);
}

status.IsRebuilding = true;
status.PopulatorStatuses = where.Select(x => new PopulatorStatus(x.GetType().Name));
}

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<string, object>()
{
{ "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<PopulatorStatus> { newPopulatorStatus };
examineIndex.IndexItems(
[
new ValueSet(
populator,
"populator",
new Dictionary<string, object>()
{
{ "isRunning", isRunning },
{ "currentBatch", currentBatch },
{ "totalBatches", totalBatches }
})
]);
}

Check warning on line 91 in src/Umbraco.Infrastructure/Examine/IndexRebuildStatusManager.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

❌ New issue: Excess Number of Function Arguments

UpdatePopulatorStatus has 5 arguments, threshold = 4. This function has too many arguments, indicating a lack of encapsulation. Avoid adding more arguments.
}
Loading
Loading