Browse Source

add database cleaner (#1853)

* fix broken tests

* add database cleaner
pull/1854/head
Jason Dove 1 year ago committed by GitHub
parent
commit
a24592a8c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs
  2. 2
      ErsatzTV.Core/Domain/MediaItem/MediaItem.cs
  3. 14
      ErsatzTV.Core/SystemStartup.cs
  4. 4
      ErsatzTV.Infrastructure/Health/Checks/UnavailableHealthCheck.cs
  5. 50
      ErsatzTV/Services/RunOnce/DatabaseCleanerService.cs
  6. 6
      ErsatzTV/Services/RunOnce/RebuildSearchIndexService.cs
  7. 1
      ErsatzTV/Startup.cs

2
ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs

@ -60,6 +60,7 @@ public class PlaylistEnumeratorTests @@ -60,6 +60,7 @@ public class PlaylistEnumeratorTests
repo,
playlistItemMap,
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
CancellationToken.None);
enumerator.MoveNext();
@ -123,6 +124,7 @@ public class PlaylistEnumeratorTests @@ -123,6 +124,7 @@ public class PlaylistEnumeratorTests
repo,
playlistItemMap,
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
CancellationToken.None);
enumerator.MoveNext();

2
ErsatzTV.Core/Domain/MediaItem/MediaItem.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
namespace ErsatzTV.Core.Domain;
public class MediaItem
public abstract class MediaItem
{
public int Id { get; set; }
public int LibraryPathId { get; set; }

14
ErsatzTV.Core/SystemStartup.cs

@ -3,11 +3,13 @@ namespace ErsatzTV.Core; @@ -3,11 +3,13 @@ namespace ErsatzTV.Core;
public class SystemStartup : IDisposable
{
private readonly SemaphoreSlim _databaseStartup = new(0, 100);
private readonly SemaphoreSlim _databaseCleaned = new(0, 100);
private readonly SemaphoreSlim _searchIndexStartup = new(0, 100);
private bool _disposedValue;
public bool IsDatabaseReady { get; private set; }
public bool IsDatabaseCleaned { get; private set; }
public bool IsSearchIndexReady { get; private set; }
public void Dispose()
@ -17,11 +19,15 @@ public class SystemStartup : IDisposable @@ -17,11 +19,15 @@ public class SystemStartup : IDisposable
}
public event EventHandler OnDatabaseReady;
public event EventHandler OnDatabaseCleaned;
public event EventHandler OnSearchIndexReady;
public async Task WaitForDatabase(CancellationToken cancellationToken) =>
await _databaseStartup.WaitAsync(cancellationToken);
public async Task WaitForDatabaseCleaned(CancellationToken cancellationToken) =>
await _databaseCleaned.WaitAsync(cancellationToken);
public async Task WaitForSearchIndex(CancellationToken cancellationToken) =>
await _searchIndexStartup.WaitAsync(cancellationToken);
@ -32,6 +38,13 @@ public class SystemStartup : IDisposable @@ -32,6 +38,13 @@ public class SystemStartup : IDisposable
OnDatabaseReady?.Invoke(this, EventArgs.Empty);
}
public void DatabaseIsCleaned()
{
_databaseCleaned.Release(100);
IsDatabaseCleaned = true;
OnDatabaseCleaned?.Invoke(this, EventArgs.Empty);
}
public void SearchIndexIsReady()
{
_searchIndexStartup.Release(100);
@ -46,6 +59,7 @@ public class SystemStartup : IDisposable @@ -46,6 +59,7 @@ public class SystemStartup : IDisposable
if (disposing)
{
_databaseStartup.Dispose();
_databaseCleaned.Dispose();
_searchIndexStartup.Dispose();
}

4
ErsatzTV.Infrastructure/Health/Checks/UnavailableHealthCheck.cs

@ -50,7 +50,9 @@ public class UnavailableHealthCheck : BaseHealthCheck, IUnavailableHealthCheck @@ -50,7 +50,9 @@ public class UnavailableHealthCheck : BaseHealthCheck, IUnavailableHealthCheck
.Include(mi => (mi as Show).ShowMetadata)
.Include(mi => (mi as Season).Show)
.ThenInclude(s => s.ShowMetadata)
.Include(mi => (mi as Season).SeasonMetadata);
.Include(mi => (mi as Season).SeasonMetadata)
.Include(mi => (mi as Image).MediaVersions)
.ThenInclude(mv => mv.MediaFiles);
List<MediaItem> five = await mediaItems
.OrderBy(mi => mi.Id)

50
ErsatzTV/Services/RunOnce/DatabaseCleanerService.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
using Dapper;
using ErsatzTV.Core;
using ErsatzTV.Infrastructure.Data;
namespace ErsatzTV.Services.RunOnce;
public class DatabaseCleanerService(
IServiceScopeFactory serviceScopeFactory,
ILogger<DatabaseCleanerService> logger,
SystemStartup systemStartup)
: BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Yield();
await systemStartup.WaitForDatabase(stoppingToken);
if (stoppingToken.IsCancellationRequested)
{
return;
}
logger.LogInformation("Cleaning database");
using IServiceScope scope = serviceScopeFactory.CreateScope();
await using TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
// some old version deleted items in a way that MediaItem was left over without
// any corresponding Movie/Show/etc.
// this cleans out that old invalid data
await dbContext.Connection.ExecuteAsync(
"""
delete
from MediaItem
where Id not in (select Id from Movie)
and Id not in (select Id from Show)
and Id not in (select Id from Season)
and Id not in (select Id from Episode)
and Id not in (select Id from OtherVideo)
and Id not in (select Id from MusicVideo)
and Id not in (select Id from Song)
and Id not in (select Id from Artist)
and Id not in (select Id from Image)
""");
systemStartup.DatabaseIsCleaned();
logger.LogInformation("Done cleaning database");
}
}

6
ErsatzTV/Services/RunOnce/RebuildSearchIndexService.cs

@ -25,6 +25,12 @@ public class RebuildSearchIndexService : BackgroundService @@ -25,6 +25,12 @@ public class RebuildSearchIndexService : BackgroundService
return;
}
await _systemStartup.WaitForDatabaseCleaned(stoppingToken);
if (stoppingToken.IsCancellationRequested)
{
return;
}
using IServiceScope scope = _serviceScopeFactory.CreateScope();
IMediator mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
await mediator.Send(new RebuildSearchIndex(), stoppingToken);

1
ErsatzTV/Startup.cs

@ -710,6 +710,7 @@ public class Startup @@ -710,6 +710,7 @@ public class Startup
// run-once/blocking startup services
services.AddHostedService<EndpointValidatorService>();
services.AddHostedService<DatabaseMigratorService>();
services.AddHostedService<DatabaseCleanerService>();
services.AddHostedService<LoadLoggingLevelService>();
services.AddHostedService<CacheCleanerService>();
services.AddHostedService<ResourceExtractorService>();

Loading…
Cancel
Save