diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Indexer/RebuildIndexerController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Indexer/RebuildIndexerController.cs
index cba2252991..f9093ffd3b 100644
--- a/src/Umbraco.Cms.Api.Management/Controllers/Indexer/RebuildIndexerController.cs
+++ b/src/Umbraco.Cms.Api.Management/Controllers/Indexer/RebuildIndexerController.cs
@@ -26,9 +26,9 @@ public class RebuildIndexerController : IndexerControllerBase
}
///
- /// Rebuilds the index
+ /// Rebuilds the index.
///
- ///
+ /// The name of the index to rebuild.
///
[HttpPost("{indexName}/rebuild")]
[MapToApiVersion("1.0")]
@@ -36,7 +36,7 @@ public class RebuildIndexerController : IndexerControllerBase
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status409Conflict)]
[ProducesResponseType(StatusCodes.Status200OK)]
- public Task Rebuild(CancellationToken cancellationToken, string indexName)
+ public async Task Rebuild(CancellationToken cancellationToken, string indexName)
{
if (!_examineManager.TryGetIndex(indexName, out IIndex? index))
{
@@ -48,7 +48,7 @@ public class RebuildIndexerController : IndexerControllerBase
Type = "Error",
};
- return Task.FromResult(NotFound(invalidModelProblem));
+ return NotFound(invalidModelProblem);
}
if (!_indexingRebuilderService.CanRebuild(index.Name))
@@ -57,19 +57,19 @@ public class RebuildIndexerController : IndexerControllerBase
{
Title = "Could not validate the populator",
Detail =
- $"The index {index?.Name} could not be rebuilt because we could not validate its associated {typeof(IIndexPopulator)}",
+ $"The index {index.Name} could not be rebuilt because we could not validate its associated {typeof(IIndexPopulator)}",
Status = StatusCodes.Status400BadRequest,
Type = "Error",
};
- return Task.FromResult(BadRequest(invalidModelProblem));
+ return BadRequest(invalidModelProblem);
}
_logger.LogInformation("Rebuilding index '{IndexName}'", indexName);
- if (_indexingRebuilderService.TryRebuild(index, indexName))
+ if (await _indexingRebuilderService.TryRebuildAsync(index, indexName))
{
- return Task.FromResult(Ok());
+ return Ok();
}
var problemDetails = new ProblemDetails
@@ -80,6 +80,6 @@ public class RebuildIndexerController : IndexerControllerBase
Type = "Error",
};
- return Task.FromResult(Conflict(problemDetails));
+ return Conflict(problemDetails);
}
}
diff --git a/src/Umbraco.Cms.Api.Management/Factories/IIndexPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IIndexPresentationFactory.cs
index 7c5529fab9..d7b5ed4ea4 100644
--- a/src/Umbraco.Cms.Api.Management/Factories/IIndexPresentationFactory.cs
+++ b/src/Umbraco.Cms.Api.Management/Factories/IIndexPresentationFactory.cs
@@ -5,5 +5,8 @@ namespace Umbraco.Cms.Api.Management.Factories;
public interface IIndexPresentationFactory
{
+ [Obsolete("Use CreateAsync() instead. Scheduled for removal in v19.")]
IndexResponseModel Create(IIndex index);
+
+ Task CreateAsync(IIndex index) => Task.FromResult(Create(index));
}
diff --git a/src/Umbraco.Cms.Api.Management/Factories/IndexPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IndexPresentationFactory.cs
index 116e3f9743..c5fd7a3ce7 100644
--- a/src/Umbraco.Cms.Api.Management/Factories/IndexPresentationFactory.cs
+++ b/src/Umbraco.Cms.Api.Management/Factories/IndexPresentationFactory.cs
@@ -28,21 +28,17 @@ public class IndexPresentationFactory : IIndexPresentationFactory
_logger = logger;
}
- [Obsolete("Use the non obsolete method instead. Scheduled for removal in v17")]
- public IndexPresentationFactory(IIndexDiagnosticsFactory indexDiagnosticsFactory, IIndexRebuilder indexRebuilder, IIndexingRebuilderService indexingRebuilderService)
- :this(
- indexDiagnosticsFactory,
- indexRebuilder,
- indexingRebuilderService,
- StaticServiceProvider.Instance.GetRequiredService>())
- {
- }
-
+ ///
+ [Obsolete("Use CreateAsync() instead. Scheduled for removal in v19.")]
public IndexResponseModel Create(IIndex index)
+ => CreateAsync(index).GetAwaiter().GetResult();
+
+ ///
+ public async Task CreateAsync(IIndex index)
{
var isCorrupt = !TryGetSearcherName(index, out var searcherName);
- if (_indexingRebuilderService.IsRebuilding(index.Name))
+ if (await _indexingRebuilderService.IsRebuildingAsync(index.Name))
{
return new IndexResponseModel
{
@@ -63,7 +59,7 @@ public class IndexPresentationFactory : IIndexPresentationFactory
var properties = new Dictionary();
- foreach (var property in indexDiag.Metadata)
+ foreach (KeyValuePair property in indexDiag.Metadata)
{
if (property.Value is null)
{
@@ -71,7 +67,7 @@ public class IndexPresentationFactory : IIndexPresentationFactory
}
else
{
- var propertyType = property.Value.GetType();
+ Type propertyType = property.Value.GetType();
properties[property.Key] = propertyType.IsClass && !propertyType.IsArray ? property.Value?.ToString() : property.Value;
}
}
diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs
index 59d1c68614..80ea4fd2ff 100644
--- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs
+++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Examine.cs
@@ -82,7 +82,7 @@ public static partial class UmbracoBuilderExtensions
builder.AddNotificationHandler();
builder.AddNotificationHandler();
builder.AddNotificationHandler();
- builder.AddNotificationHandler();
+ builder.AddNotificationAsyncHandler();
builder.AddNotificationHandler();
diff --git a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs
index edf8deca86..4f03a1fbe3 100644
--- a/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs
+++ b/src/Umbraco.Infrastructure/Examine/ExamineIndexRebuilder.cs
@@ -6,18 +6,20 @@ using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Runtime;
using Umbraco.Cms.Core.Services;
-using Umbraco.Cms.Infrastructure.HostedServices;
+using Umbraco.Cms.Core.Services.OperationStatus;
+using Umbraco.Cms.Infrastructure.Models;
namespace Umbraco.Cms.Infrastructure.Examine;
internal class ExamineIndexRebuilder : IIndexRebuilder
{
- private readonly IBackgroundTaskQueue _backgroundTaskQueue;
+ private const string RebuildAllOperationTypeName = "RebuildAllExamineIndexes";
+
private readonly IExamineManager _examineManager;
private readonly ILogger _logger;
private readonly IMainDom _mainDom;
private readonly IEnumerable _populators;
- private readonly object _rebuildLocker = new();
+ private readonly ILongRunningOperationService _longRunningOperationService;
private readonly IRuntimeState _runtimeState;
///
@@ -29,16 +31,17 @@ internal class ExamineIndexRebuilder : IIndexRebuilder
ILogger logger,
IExamineManager examineManager,
IEnumerable populators,
- IBackgroundTaskQueue backgroundTaskQueue)
+ ILongRunningOperationService longRunningOperationService)
{
_mainDom = mainDom;
_runtimeState = runtimeState;
_logger = logger;
_examineManager = examineManager;
_populators = populators;
- _backgroundTaskQueue = backgroundTaskQueue;
+ _longRunningOperationService = longRunningOperationService;
}
+ ///
public bool CanRebuild(string indexName)
{
if (!_examineManager.TryGetIndex(indexName, out IIndex index))
@@ -49,180 +52,149 @@ internal class ExamineIndexRebuilder : IIndexRebuilder
return _populators.Any(x => x.IsRegistered(index));
}
+ ///
+ [Obsolete("Use RebuildIndexAsync() instead. Scheduled for removal in v19.")]
public virtual void RebuildIndex(string indexName, TimeSpan? delay = null, bool useBackgroundThread = true)
+ => RebuildIndexAsync(indexName, delay, useBackgroundThread).GetAwaiter().GetResult();
+
+ ///
+ public virtual async Task> RebuildIndexAsync(string indexName, TimeSpan? delay = null, bool useBackgroundThread = true)
{
- if (delay == null)
- {
- delay = TimeSpan.Zero;
- }
+ delay ??= TimeSpan.Zero;
if (!CanRun())
{
- return;
+ return Attempt.Fail(IndexRebuildResult.NotAllowedToRun);
}
- if (useBackgroundThread)
- {
- _logger.LogInformation("Starting async background thread for rebuilding index {indexName}.", indexName);
-
- _backgroundTaskQueue.QueueBackgroundWorkItem(
- cancellationToken =>
- {
- // Do not flow AsyncLocal to the child thread
- using (ExecutionContext.SuppressFlow())
- {
- Task.Run(() => RebuildIndex(indexName, delay.Value, cancellationToken));
-
- // immediately return so the queue isn't waiting.
- return Task.CompletedTask;
- }
- });
- }
- else
- {
- RebuildIndex(indexName, delay.Value, CancellationToken.None);
- }
- }
-
- public virtual void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true)
- {
- if (delay == null)
- {
- delay = TimeSpan.Zero;
- }
-
- if (!CanRun())
- {
- return;
- }
-
- if (useBackgroundThread)
- {
- if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ Attempt attempt = await _longRunningOperationService.RunAsync(
+ GetRebuildOperationTypeName(indexName),
+ async ct =>
{
- _logger.LogDebug($"Queuing background job for {nameof(RebuildIndexes)}.");
- }
+ await RebuildIndex(indexName, delay.Value, ct);
+ return Task.CompletedTask;
+ },
+ allowConcurrentExecution: false,
+ runInBackground: useBackgroundThread);
- _backgroundTaskQueue.QueueBackgroundWorkItem(
- cancellationToken =>
- {
- // Do not flow AsyncLocal to the child thread
- using (ExecutionContext.SuppressFlow())
- {
- // This is a fire/forget task spawned by the background thread queue (which means we
- // don't need to worry about ExecutionContext flowing).
- Task.Run(() => RebuildIndexes(onlyEmptyIndexes, delay.Value, cancellationToken));
-
- // immediately return so the queue isn't waiting.
- return Task.CompletedTask;
- }
- });
- }
- else
+ if (attempt.Success)
{
- RebuildIndexes(onlyEmptyIndexes, delay.Value, CancellationToken.None);
+ return Attempt.Succeed(IndexRebuildResult.Success);
}
+
+ return attempt.Status switch
+ {
+ LongRunningOperationEnqueueStatus.AlreadyRunning => Attempt.Fail(IndexRebuildResult.AlreadyRebuilding),
+ _ => Attempt.Fail(IndexRebuildResult.Unknown),
+ };
}
+ ///
+ [Obsolete("Use RebuildIndexesAsync() instead. Scheduled for removal in v19.")]
+ public virtual void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true)
+ => RebuildIndexesAsync(onlyEmptyIndexes, delay, useBackgroundThread).GetAwaiter().GetResult();
+
+ ///
+ public virtual async Task> RebuildIndexesAsync(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true)
+ {
+ delay ??= TimeSpan.Zero;
+
+ if (!CanRun())
+ {
+ return Attempt.Fail(IndexRebuildResult.NotAllowedToRun);
+ }
+
+ Attempt attempt = await _longRunningOperationService.RunAsync(
+ RebuildAllOperationTypeName,
+ async ct =>
+ {
+ await RebuildIndexes(onlyEmptyIndexes, delay.Value, ct);
+ return Task.CompletedTask;
+ },
+ allowConcurrentExecution: false,
+ runInBackground: useBackgroundThread);
+
+ if (attempt.Success)
+ {
+ return Attempt.Succeed(IndexRebuildResult.Success);
+ }
+
+ return attempt.Status switch
+ {
+ LongRunningOperationEnqueueStatus.AlreadyRunning => Attempt.Fail(IndexRebuildResult.AlreadyRebuilding),
+ _ => Attempt.Fail(IndexRebuildResult.Unknown),
+ };
+ }
+
+ ///
+ public async Task IsRebuildingAsync(string indexName)
+ => (await _longRunningOperationService.GetByTypeAsync(GetRebuildOperationTypeName(indexName), 0, 0)).Total != 0;
+
+ private static string GetRebuildOperationTypeName(string indexName) => $"RebuildExamineIndex-{indexName}";
+
private bool CanRun() => _mainDom.IsMainDom && _runtimeState.Level == RuntimeLevel.Run;
- private void RebuildIndex(string indexName, TimeSpan delay, CancellationToken cancellationToken)
+ private async Task RebuildIndex(string indexName, TimeSpan delay, CancellationToken cancellationToken)
{
if (delay > TimeSpan.Zero)
{
- Thread.Sleep(delay);
+ await Task.Delay(delay, cancellationToken);
}
- try
+ if (!_examineManager.TryGetIndex(indexName, out IIndex index))
{
- if (!Monitor.TryEnter(_rebuildLocker))
- {
- _logger.LogWarning(
- "Call was made to RebuildIndexes but the task runner for rebuilding is already running");
- }
- else
- {
- if (!_examineManager.TryGetIndex(indexName, out IIndex index))
- {
- throw new InvalidOperationException($"No index found with name {indexName}");
- }
-
- index.CreateIndex(); // clear the index
- foreach (IIndexPopulator populator in _populators)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return;
- }
-
- populator.Populate(index);
- }
- }
+ throw new InvalidOperationException($"No index found with name {indexName}");
}
- finally
+
+ index.CreateIndex(); // clear the index
+ foreach (IIndexPopulator populator in _populators)
{
- if (Monitor.IsEntered(_rebuildLocker))
+ if (cancellationToken.IsCancellationRequested)
{
- Monitor.Exit(_rebuildLocker);
+ return;
}
+
+ populator.Populate(index);
}
}
- private void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan delay, CancellationToken cancellationToken)
+ private async Task RebuildIndexes(bool onlyEmptyIndexes, TimeSpan delay, CancellationToken cancellationToken)
{
if (delay > TimeSpan.Zero)
{
- Thread.Sleep(delay);
+ await Task.Delay(delay, cancellationToken);
}
- try
+ // If an index exists but it has zero docs we'll consider it empty and rebuild
+ IIndex[] indexes = (onlyEmptyIndexes
+ ? _examineManager.Indexes.Where(ShouldRebuild)
+ : _examineManager.Indexes).ToArray();
+
+ if (indexes.Length == 0)
{
- 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(ShouldRebuild)
- : _examineManager.Indexes).ToArray();
-
- if (indexes.Length == 0)
- {
- return;
- }
-
- foreach (IIndex index in indexes)
- {
- index.CreateIndex(); // clear the index
- }
-
- // run each populator over the indexes
- foreach (IIndexPopulator populator in _populators)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- return;
- }
-
- try
- {
- populator.Populate(indexes);
- }
- catch (Exception e)
- {
- _logger.LogError(e, "Index populating failed for populator {Populator}", populator.GetType());
- }
- }
- }
+ return;
}
- finally
+
+ foreach (IIndex index in indexes)
{
- if (Monitor.IsEntered(_rebuildLocker))
+ index.CreateIndex(); // clear the index
+ }
+
+ // run each populator over the indexes
+ foreach (IIndexPopulator populator in _populators)
+ {
+ if (cancellationToken.IsCancellationRequested)
{
- Monitor.Exit(_rebuildLocker);
+ return;
+ }
+
+ try
+ {
+ populator.Populate(indexes);
+ }
+ catch (Exception e)
+ {
+ _logger.LogError(e, "Index populating failed for populator {Populator}", populator.GetType());
}
}
}
diff --git a/src/Umbraco.Infrastructure/Examine/IIndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/IIndexRebuilder.cs
index a85c551b8d..78574b01f2 100644
--- a/src/Umbraco.Infrastructure/Examine/IIndexRebuilder.cs
+++ b/src/Umbraco.Infrastructure/Examine/IIndexRebuilder.cs
@@ -1,10 +1,69 @@
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Infrastructure.Models;
+
namespace Umbraco.Cms.Infrastructure.Examine;
+///
+/// Interface for rebuilding search indexes.
+///
public interface IIndexRebuilder
{
+ ///
+ /// Checks if the specified index can be rebuilt.
+ ///
+ /// The name of the index to check.
+ /// Whether the index can be rebuilt.
bool CanRebuild(string indexName);
+ ///
+ /// Rebuilds the specified index.
+ ///
+ /// The name of the index to rebuild.
+ /// The delay before starting the rebuild.
+ /// Whether to use a background thread for the rebuild.
+ [Obsolete("Use RebuildIndexesAsync() instead. Scheduled for removal in V19.")]
void RebuildIndex(string indexName, TimeSpan? delay = null, bool useBackgroundThread = true);
+ ///
+ /// Rebuilds the specified index.
+ ///
+ /// The name of the index to rebuild.
+ /// The delay before starting the rebuild.
+ /// Whether to use a background thread for the rebuild.
+ /// A task representing the asynchronous operation.
+ Task> RebuildIndexAsync(string indexName, TimeSpan? delay = null, bool useBackgroundThread = true)
+ {
+ RebuildIndex(indexName, delay, useBackgroundThread);
+ return Task.FromResult(Attempt.Succeed(IndexRebuildResult.Success));
+ }
+
+ ///
+ /// Rebuilds all indexes, or only those that are empty.
+ ///
+ /// Whether to only rebuild empty indexes.
+ /// The delay before starting the rebuild.
+ /// Whether to use a background thread for the rebuild.
+ [Obsolete("Use RebuildIndexesAsync() instead. Scheduled for removal in V19.")]
void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true);
+
+ ///
+ /// Rebuilds all indexes, or only those that are empty.
+ ///
+ /// Whether to only rebuild empty indexes.
+ /// The delay before starting the rebuild.
+ /// Whether to use a background thread for the rebuild.
+ /// A task representing the asynchronous operation.
+ Task> RebuildIndexesAsync(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true)
+ {
+ RebuildIndexes(onlyEmptyIndexes, delay, useBackgroundThread);
+ return Task.FromResult(Attempt.Succeed(IndexRebuildResult.Success));
+ }
+
+ ///
+ /// Checks if the specified index is currently being rebuilt.
+ ///
+ /// The name of the index to check.
+ /// Whether the index is currently being rebuilt.
+ // TODO (v19): Remove the default implementation.
+ Task IsRebuildingAsync(string indexName) => throw new NotImplementedException();
}
diff --git a/src/Umbraco.Infrastructure/Examine/NoopIndexRebuilder.cs b/src/Umbraco.Infrastructure/Examine/NoopIndexRebuilder.cs
index bfa1c9f0f0..04f1efd59c 100644
--- a/src/Umbraco.Infrastructure/Examine/NoopIndexRebuilder.cs
+++ b/src/Umbraco.Infrastructure/Examine/NoopIndexRebuilder.cs
@@ -7,4 +7,6 @@ internal sealed class NoopIndexRebuilder : IIndexRebuilder
public void RebuildIndex(string indexName, TimeSpan? delay = null, bool useBackgroundThread = true) {}
public void RebuildIndexes(bool onlyEmptyIndexes, TimeSpan? delay = null, bool useBackgroundThread = true) {}
+
+ public Task IsRebuildingAsync(string indexName) => Task.FromResult(false);
}
diff --git a/src/Umbraco.Infrastructure/Models/IndexRebuildResult.cs b/src/Umbraco.Infrastructure/Models/IndexRebuildResult.cs
new file mode 100644
index 0000000000..2d34ca9522
--- /dev/null
+++ b/src/Umbraco.Infrastructure/Models/IndexRebuildResult.cs
@@ -0,0 +1,27 @@
+namespace Umbraco.Cms.Infrastructure.Models;
+
+///
+/// Represents the status of an index rebuild trigger.
+///
+public enum IndexRebuildResult
+{
+ ///
+ /// The rebuild was either successful or enqueued successfully.
+ ///
+ Success,
+
+ ///
+ /// The index is already being rebuilt.
+ ///
+ AlreadyRebuilding,
+
+ ///
+ /// The index rebuild was not scheduled because it's not allowed to run at this time.
+ ///
+ NotAllowedToRun,
+
+ ///
+ /// The index rebuild was not scheduled due to an unknown error.
+ ///
+ Unknown,
+}
diff --git a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Language.cs b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Language.cs
index cf8a2e1ab3..7092050edf 100644
--- a/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Language.cs
+++ b/src/Umbraco.Infrastructure/Search/IndexingNotificationHandler.Language.cs
@@ -5,7 +5,9 @@ using Umbraco.Cms.Infrastructure.Examine;
namespace Umbraco.Cms.Infrastructure.Search;
-public sealed class LanguageIndexingNotificationHandler : INotificationHandler
+public sealed class LanguageIndexingNotificationHandler :
+ INotificationHandler,
+ INotificationAsyncHandler
{
private readonly IIndexRebuilder _indexRebuilder;
private readonly IUmbracoIndexingHandler _umbracoIndexingHandler;
@@ -19,14 +21,20 @@ public sealed class LanguageIndexingNotificationHandler : INotificationHandler
+ [Obsolete("Use HandleAsync instead. Scheduled for removal in V19.")]
public void Handle(LanguageCacheRefresherNotification args)
+ => HandleAsync(args, CancellationToken.None).GetAwaiter().GetResult();
+
+ ///
+ public async Task HandleAsync(LanguageCacheRefresherNotification notification, CancellationToken cancellationToken)
{
if (!_umbracoIndexingHandler.Enabled)
{
return;
}
- if (!(args.MessageObject is LanguageCacheRefresher.JsonPayload[] payloads))
+ if (notification.MessageObject is not LanguageCacheRefresher.JsonPayload[] payloads)
{
return;
}
@@ -37,14 +45,14 @@ public sealed class LanguageIndexingNotificationHandler : INotificationHandler
- x.ChangeType == LanguageCacheRefresher.JsonPayload.LanguageChangeType.ChangeCulture
- || x.ChangeType == LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove);
+ x.ChangeType is LanguageCacheRefresher.JsonPayload.LanguageChangeType.ChangeCulture
+ or LanguageCacheRefresher.JsonPayload.LanguageChangeType.Remove);
if (removedOrCultureChanged)
{
// if a lang is removed or it's culture has changed, we need to rebuild the indexes since
// field names and values in the index have a string culture value.
- _indexRebuilder.RebuildIndexes(false);
+ _ = await _indexRebuilder.RebuildIndexesAsync(false);
}
}
}
diff --git a/src/Umbraco.Infrastructure/Services/IIndexingRebuilderService.cs b/src/Umbraco.Infrastructure/Services/IIndexingRebuilderService.cs
index c23eb7115e..3f358c2bca 100644
--- a/src/Umbraco.Infrastructure/Services/IIndexingRebuilderService.cs
+++ b/src/Umbraco.Infrastructure/Services/IIndexingRebuilderService.cs
@@ -2,10 +2,48 @@
namespace Umbraco.Cms.Infrastructure.Services;
+///
+/// Indexing rebuilder service.
+///
public interface IIndexingRebuilderService
{
+ ///
+ /// Checks if the index can be rebuilt.
+ ///
+ /// The name of the index to check.
+ /// Whether the index can be rebuilt.
bool CanRebuild(string indexName);
+
+ ///
+ /// Tries to rebuild the specified index.
+ ///
+ /// The index to rebuild.
+ /// The name of the index to rebuild.
+ /// Whether the rebuild was successfully scheduled.
+ [Obsolete("Use TryRebuildAsync() instead. Scheduled for removal in V19.")]
bool TryRebuild(IIndex index, string indexName);
+ ///
+ /// Tries to rebuild the specified index.
+ ///
+ /// The index to rebuild.
+ /// The name of the index to rebuild.
+ /// Whether the rebuild was successfully scheduled.
+ Task TryRebuildAsync(IIndex index, string indexName) => Task.FromResult(TryRebuild(index, indexName));
+
+ ///
+ /// Checks if the specified index is currently being rebuilt.
+ ///
+ /// The name of the index to check.
+ /// Whether the index is currently being rebuilt.
+ [Obsolete("Use IsRebuildingAsync() instead. Scheduled for removal in V19.")]
bool IsRebuilding(string indexName);
+
+ ///
+ /// Checks if the specified index is currently being rebuilt.
+ ///
+ /// The name of the index to rebuild.
+ /// Whether the index is currently being rebuilt.
+ Task IsRebuildingAsync(string indexName) =>
+ Task.FromResult(IsRebuilding(indexName));
}
diff --git a/src/Umbraco.Infrastructure/Services/IndexingRebuilderService.cs b/src/Umbraco.Infrastructure/Services/IndexingRebuilderService.cs
index c014277b6b..1263f52e5e 100644
--- a/src/Umbraco.Infrastructure/Services/IndexingRebuilderService.cs
+++ b/src/Umbraco.Infrastructure/Services/IndexingRebuilderService.cs
@@ -1,18 +1,27 @@
using Examine;
using Microsoft.Extensions.Logging;
+using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Infrastructure.Examine;
+using Umbraco.Cms.Infrastructure.Models;
namespace Umbraco.Cms.Infrastructure.Services;
+///
public class IndexingRebuilderService : IIndexingRebuilderService
{
- private const string IsRebuildingIndexRuntimeCacheKeyPrefix = "temp_indexing_op_";
-
- private readonly IAppPolicyCache _runtimeCache;
private readonly IIndexRebuilder _indexRebuilder;
private readonly ILogger _logger;
+ public IndexingRebuilderService(
+ IIndexRebuilder indexRebuilder,
+ ILogger logger)
+ {
+ _indexRebuilder = indexRebuilder;
+ _logger = logger;
+ }
+
+ [Obsolete("Use the non-obsolete constructor instead. Scheduled for removal in V19.")]
public IndexingRebuilderService(
AppCaches runtimeCache,
IIndexRebuilder indexRebuilder,
@@ -20,12 +29,18 @@ public class IndexingRebuilderService : IIndexingRebuilderService
{
_indexRebuilder = indexRebuilder;
_logger = logger;
- _runtimeCache = runtimeCache.RuntimeCache;
}
+ ///
public bool CanRebuild(string indexName) => _indexRebuilder.CanRebuild(indexName);
+ ///
+ [Obsolete("Use TryRebuildAsync instead. Scheduled for removal in V19.")]
public bool TryRebuild(IIndex index, string indexName)
+ => TryRebuildAsync(index, indexName).GetAwaiter().GetResult();
+
+ ///
+ public async Task TryRebuildAsync(IIndex index, string indexName)
{
// Remove it in case there's a handler there already
index.IndexOperationComplete -= Indexer_IndexOperationComplete;
@@ -35,11 +50,10 @@ public class IndexingRebuilderService : IIndexingRebuilderService
try
{
- Set(indexName);
- _indexRebuilder.RebuildIndex(indexName);
- return true;
+ Attempt attempt = await _indexRebuilder.RebuildIndexAsync(indexName);
+ return attempt.Success;
}
- catch(Exception exception)
+ catch (Exception exception)
{
// Ensure it's not listening
index.IndexOperationComplete -= Indexer_IndexOperationComplete;
@@ -48,25 +62,14 @@ public class IndexingRebuilderService : IIndexingRebuilderService
}
}
- private void Set(string indexName)
- {
- var cacheKey = IsRebuildingIndexRuntimeCacheKeyPrefix + indexName;
-
- // 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));
- }
-
- private void Clear(string? indexName)
- {
- var cacheKey = IsRebuildingIndexRuntimeCacheKeyPrefix + indexName;
- _runtimeCache.Clear(cacheKey);
- }
-
+ ///
+ [Obsolete("Use IsRebuildingAsync() instead. Scheduled for removal in V19.")]
public bool IsRebuilding(string indexName)
- {
- var cacheKey = IsRebuildingIndexRuntimeCacheKeyPrefix + indexName;
- return _runtimeCache.Get(cacheKey) is not null;
- }
+ => IsRebuildingAsync(indexName).GetAwaiter().GetResult();
+
+ ///
+ public Task IsRebuildingAsync(string indexName)
+ => _indexRebuilder.IsRebuildingAsync(indexName);
private void Indexer_IndexOperationComplete(object? sender, EventArgs e)
{
@@ -80,8 +83,6 @@ public class IndexingRebuilderService : IIndexingRebuilderService
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
}
- _logger.LogInformation($"Rebuilding index '{indexer?.Name}' done.");
-
- Clear(indexer?.Name);
+ _logger.LogInformation("Rebuilding index '{IndexerName}' done.", indexer?.Name);
}
}
diff --git a/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs b/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs
index 021eaaa2ba..958d328c1b 100644
--- a/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs
+++ b/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs
@@ -158,14 +158,14 @@ public static class UmbracoBuilderExtensions
ILogger logger,
IExamineManager examineManager,
IEnumerable populators,
- IBackgroundTaskQueue backgroundTaskQueue)
+ ILongRunningOperationService longRunningOperationService)
: base(
mainDom,
runtimeState,
logger,
examineManager,
populators,
- backgroundTaskQueue)
+ longRunningOperationService)
{
}