diff --git a/CHANGELOG.md b/CHANGELOG.md index fdb5d792..e7f5291a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - A deep scan can be used to fix all movies, otherwise any future updates made to JF movies will correctly sync to ETV - Automatically generate JWT tokens to allow channel previews of protected streams +### Changed +- Log search index updates under scanner category at debug level, to indicate a potential cause for the UI being out of date +- Batch search index updates to keep pace with library scans + - Previously, search index updates would slowly process over minutes/hours after library scans completed + - Search index updates should now complete at the same time as library scans + ## [0.8.5-beta] - 2024-01-30 ### Added - Respect browser's `Accept-Language` header for date time display diff --git a/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs b/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs index e3b2696d..ad72da6b 100644 --- a/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs +++ b/ErsatzTV.Application/Libraries/Commands/CallLibraryScannerHandler.cs @@ -25,6 +25,9 @@ public abstract class CallLibraryScannerHandler private readonly IDbContextFactory _dbContextFactory; private readonly IMediator _mediator; private readonly IRuntimeInfo _runtimeInfo; + private readonly List _toReindex = []; + private readonly List _toRemove = []; + private readonly int _batchSize = 100; private string _libraryName; protected CallLibraryScannerHandler( @@ -65,6 +68,18 @@ public abstract class CallLibraryScannerHandler { return BaseError.New($"ErsatzTV.Scanner exited with code {process.ExitCode}"); } + + if (_toReindex.Count > 0) + { + await _channel.WriteAsync(new ReindexMediaItems(_toReindex.ToArray()), cancellationToken); + _toReindex.Clear(); + } + + if (_toRemove.Count > 0) + { + await _channel.WriteAsync(new RemoveMediaItems(_toReindex.ToArray()), cancellationToken); + _toRemove.Clear(); + } } catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException) { @@ -122,6 +137,20 @@ public abstract class CallLibraryScannerHandler _libraryName = progressUpdate.LibraryName; } + _toReindex.AddRange(progressUpdate.ItemsToReindex); + if (_toReindex.Count >= _batchSize) + { + await _channel.WriteAsync(new ReindexMediaItems(_toReindex.ToArray())); + _toReindex.Clear(); + } + + _toRemove.AddRange(progressUpdate.ItemsToRemove); + if (_toRemove.Count >= _batchSize) + { + await _channel.WriteAsync(new RemoveMediaItems(_toReindex.ToArray())); + _toRemove.Clear(); + } + if (progressUpdate.PercentComplete is not null) { var progress = new LibraryScanProgress( @@ -130,18 +159,6 @@ public abstract class CallLibraryScannerHandler await _mediator.Publish(progress); } - - if (progressUpdate.ItemsToReindex.Length > 0) - { - var reindex = new ReindexMediaItems(progressUpdate.ItemsToReindex); - await _channel.WriteAsync(reindex); - } - - if (progressUpdate.ItemsToRemove.Length > 0) - { - var remove = new RemoveMediaItems(progressUpdate.ItemsToRemove); - await _channel.WriteAsync(remove); - } } } catch (Exception ex) diff --git a/ErsatzTV/Program.cs b/ErsatzTV/Program.cs index 33040c5a..c595663c 100644 --- a/ErsatzTV/Program.cs +++ b/ErsatzTV/Program.cs @@ -66,6 +66,7 @@ public class Program // scanning .MinimumLevel.Override("ErsatzTV.Services.ScannerService", LoggingLevelSwitches.ScanningLevelSwitch) + .MinimumLevel.Override("ErsatzTV.Services.SearchIndexService", LoggingLevelSwitches.ScanningLevelSwitch) .MinimumLevel.Override("ErsatzTV.Scanner", LoggingLevelSwitches.ScanningLevelSwitch) // scheduling diff --git a/ErsatzTV/Services/SearchIndexService.cs b/ErsatzTV/Services/SearchIndexService.cs index 9143109d..483da820 100644 --- a/ErsatzTV/Services/SearchIndexService.cs +++ b/ErsatzTV/Services/SearchIndexService.cs @@ -9,13 +9,13 @@ namespace ErsatzTV.Services; public class SearchIndexService : BackgroundService { private readonly ChannelReader _channel; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServiceScopeFactory _serviceScopeFactory; public SearchIndexService( ChannelReader channel, IServiceScopeFactory serviceScopeFactory, - ILogger logger) + ILogger logger) { _channel = channel; _serviceScopeFactory = serviceScopeFactory; @@ -40,9 +40,11 @@ public class SearchIndexService : BackgroundService switch (request) { case ReindexMediaItems reindexMediaItems: + _logger.LogDebug("Reindexing media items: {MediaItemIds}", reindexMediaItems.MediaItemIds); await mediator.Send(reindexMediaItems, stoppingToken); break; case RemoveMediaItems removeMediaItems: + _logger.LogDebug("Removing media items: {MediaItemIds}", removeMediaItems.MediaItemIds); await mediator.Send(removeMediaItems, stoppingToken); break; }