async fixes (#128)
* refactor local metadata provider * resolve async warnings * more async fixes
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Metadata;
|
||||
using ErsatzTV.Infrastructure.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.Services.RunOnce
|
||||
{
|
||||
public class CacheCleanerService : IHostedService
|
||||
{
|
||||
private readonly ILogger<CacheCleanerService> _logger;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
public CacheCleanerService(
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
ILogger<CacheCleanerService> logger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using IServiceScope scope = _serviceScopeFactory.CreateScope();
|
||||
await using TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
|
||||
|
||||
if (Directory.Exists(FileSystemLayout.LegacyImageCacheFolder))
|
||||
{
|
||||
_logger.LogInformation("Migrating channel logos from legacy image cache folder");
|
||||
|
||||
List<string> logos = await dbContext.Channels
|
||||
.SelectMany(c => c.Artwork)
|
||||
.Where(a => a.ArtworkKind == ArtworkKind.Logo)
|
||||
.Map(a => a.Path)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
ILocalFileSystem localFileSystem = scope.ServiceProvider.GetRequiredService<ILocalFileSystem>();
|
||||
foreach (string logo in logos)
|
||||
{
|
||||
string legacyPath = Path.Combine(FileSystemLayout.LegacyImageCacheFolder, logo);
|
||||
if (File.Exists(legacyPath))
|
||||
{
|
||||
string subfolder = logo.Substring(0, 2);
|
||||
string newPath = Path.Combine(FileSystemLayout.LogoCacheFolder, subfolder, logo);
|
||||
await localFileSystem.CopyFile(legacyPath, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Deleting legacy image cache folder");
|
||||
Directory.Delete(FileSystemLayout.LegacyImageCacheFolder, true);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Infrastructure.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.Services.RunOnce
|
||||
{
|
||||
public class DatabaseMigratorService : IHostedService
|
||||
{
|
||||
private readonly ILogger<DatabaseMigratorService> _logger;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
|
||||
public DatabaseMigratorService(
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
ILogger<DatabaseMigratorService> logger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("Applying database migrations");
|
||||
|
||||
using IServiceScope scope = _serviceScopeFactory.CreateScope();
|
||||
await using TvContext dbContext = scope.ServiceProvider.GetRequiredService<TvContext>();
|
||||
await dbContext.Database.MigrateAsync(cancellationToken);
|
||||
await DbInitializer.Initialize(dbContext, cancellationToken);
|
||||
|
||||
_logger.LogInformation("Done applying database migrations");
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -15,50 +15,55 @@ using ErsatzTV.Infrastructure.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.Services
|
||||
{
|
||||
public class SchedulerService : IHostedService
|
||||
public class SchedulerService : BackgroundService
|
||||
{
|
||||
private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
|
||||
private readonly IEntityLocker _entityLocker;
|
||||
private readonly ILogger<SchedulerService> _logger;
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private Timer _timer;
|
||||
|
||||
public SchedulerService(
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
ChannelWriter<IBackgroundServiceRequest> channel,
|
||||
IEntityLocker entityLocker)
|
||||
IEntityLocker entityLocker,
|
||||
ILogger<SchedulerService> logger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_channel = channel;
|
||||
_entityLocker = entityLocker;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_timer = new Timer(
|
||||
async _ => await DoWork(cancellationToken),
|
||||
null,
|
||||
TimeSpan.FromSeconds(0), // fire immediately
|
||||
TimeSpan.FromHours(1)); // repeat every hour
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
await DoWork(cancellationToken);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_timer?.Change(Timeout.Infinite, 0);
|
||||
|
||||
return Task.CompletedTask;
|
||||
await Task.Delay(TimeSpan.FromHours(1), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DoWork(CancellationToken cancellationToken)
|
||||
{
|
||||
await RebuildSearchIndex(cancellationToken);
|
||||
await BuildPlayouts(cancellationToken);
|
||||
await ScanLocalMediaSources(cancellationToken);
|
||||
await ScanPlexMediaSources(cancellationToken);
|
||||
try
|
||||
{
|
||||
await RebuildSearchIndex(cancellationToken);
|
||||
await BuildPlayouts(cancellationToken);
|
||||
await ScanLocalMediaSources(cancellationToken);
|
||||
await ScanPlexMediaSources(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error during scheduler run");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task BuildPlayouts(CancellationToken cancellationToken)
|
||||
@@ -114,7 +119,7 @@ namespace ErsatzTV.Services
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RebuildSearchIndex(CancellationToken cancellationToken) =>
|
||||
await _channel.WriteAsync(new RebuildSearchIndex(), cancellationToken);
|
||||
private ValueTask RebuildSearchIndex(CancellationToken cancellationToken) =>
|
||||
_channel.WriteAsync(new RebuildSearchIndex(), cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user