Lots of Hangfire attempts to solve the lock issue. Not sure how to fix it. Added some APIs for streams.

This commit is contained in:
Joseph Milazzo 2021-03-15 13:49:13 -05:00
parent bb0a59448f
commit fad4ca4414
10 changed files with 89 additions and 28 deletions

View File

@ -128,9 +128,18 @@ namespace API.Controllers
}
[HttpGet("recently-added")]
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetRecentlyAdded(int libraryId = 0)
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetRecentlyAdded(int libraryId = 0, int limit = 20)
{
return Ok(await _unitOfWork.SeriesRepository.GetRecentlyAdded(libraryId));
return Ok(await _unitOfWork.SeriesRepository.GetRecentlyAdded(libraryId, limit));
}
[HttpGet("in-progress")]
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetInProgress(int libraryId = 0, int limit = 20)
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
return Ok(await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, limit));
}
}
}

View File

@ -11,6 +11,7 @@ using API.Interfaces;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.Logging;
namespace API.Data
@ -282,20 +283,55 @@ namespace API.Data
/// Returns a list of Series that were added within 2 weeks.
/// </summary>
/// <param name="libraryId">Library to restrict to, if 0, will apply to all libraries</param>
/// <param name="limit"></param>
/// <returns></returns>
public async Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId)
public async Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId, int limit)
{
// && (libraryId <= 0 || s.LibraryId == libraryId)
// TODO: Remove 2 week condition
var twoWeeksAgo = DateTime.Today.Subtract(TimeSpan.FromDays(14));
_logger.LogDebug("2 weeks from today is: {Date}", twoWeeksAgo);
return await _context.Series
.Where(s => s.Created > twoWeeksAgo)
.Take(20)
.Where(s => s.Created > twoWeeksAgo && (libraryId <= 0 || s.LibraryId == libraryId))
.Take(limit)
.OrderBy(s => s.Created)
.AsNoTracking()
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
.ToListAsync();
}
public async Task<IEnumerable<SeriesDto>> GetInProgress(int userId, int libraryId, int limit)
{
//&& (libraryId <= 0 || s.Series.LibraryId == libraryId)
var twoWeeksAgo = DateTime.Today.Subtract(TimeSpan.FromDays(14));
_logger.LogInformation("GetInProgress");
_logger.LogDebug("2 weeks from today is: {Date}", twoWeeksAgo);
// var series = await _context.Series
// .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new
// {
// Series = s,
// Progress = progress
// })
// .DefaultIfEmpty()
// .Where(s => s.Series.Created > twoWeeksAgo
// && s.Progress.AppUserId == userId
// && s.Progress.PagesRead > s.Series.Pages)
// .Take(limit)
// .OrderBy(s => s.Series.Created)
// .AsNoTracking()
// .Select(s => s.Series)
// .ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
// .ToListAsync();
var series = await _context.Series
.Where(s => s.Created > twoWeeksAgo) // && (libraryId <= 0 || s.LibraryId == libraryId)
.AsNoTracking()
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
.ToListAsync();
await AddSeriesModifiers(userId, series);
return series.Where(s => s.PagesRead > 0).Take(limit).ToList();
}
public async Task<IEnumerable<SeriesDto>> GetSeriesStream(int userId)

View File

@ -1,7 +1,12 @@
namespace API.Extensions
using API.Interfaces.Services;
using Microsoft.Extensions.DependencyInjection;
namespace API.Extensions
{
public class ServiceCollectionExtensions
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddStartupTask<T>(this IServiceCollection services)
where T : class, IStartupTask
=> services.AddTransient<IStartupTask, T>();
}
}

View File

@ -55,6 +55,7 @@ namespace API.Interfaces
Task<byte[]> GetVolumeCoverImageAsync(int volumeId);
Task<byte[]> GetSeriesCoverImageAsync(int seriesId);
Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId);
Task<IEnumerable<SeriesDto>> GetInProgress(int userId, int libraryId, int limit);
Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId, int limit);
}
}

View File

@ -25,6 +25,7 @@ namespace API.Middleware
public async Task InvokeAsync(HttpContext context)
{
// BUG: I think Hangfire timeouts are triggering the middleware to hijack an API call
try
{
await _next(context); // downstream middlewares or http call

View File

@ -3,6 +3,8 @@ using System.Threading.Tasks;
using API.Data;
using API.Entities;
using API.Interfaces;
using API.Interfaces.Services;
using API.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@ -40,6 +42,15 @@ namespace API
var logger = services.GetRequiredService < ILogger<Program>>();
logger.LogError(ex, "An error occurred during migration");
}
// Load all tasks from DI (TODO: This is not working)
var startupTasks = host.Services.GetServices<WarmupServicesStartupTask>();
// Execute all the tasks
foreach (var startupTask in startupTasks)
{
await startupTask.ExecuteAsync();
}
await host.RunAsync();
}

View File

@ -21,11 +21,11 @@ namespace API.Services
private readonly ICleanupService _cleanupService;
private readonly IDirectoryService _directoryService;
public static BackgroundJobServer Client => new BackgroundJobServer();
// new BackgroundJobServerOptions()
// {
// WorkerCount = 1
// }
public static BackgroundJobServer Client => new BackgroundJobServer(new BackgroundJobServerOptions()
{
WorkerCount = 1
});
public TaskScheduler(ICacheService cacheService, ILogger<TaskScheduler> logger, IScannerService scannerService,
IUnitOfWork unitOfWork, IMetadataService metadataService, IBackupService backupService, ICleanupService cleanupService,

View File

@ -33,7 +33,7 @@ namespace API.Services.Tasks
_metadataService = metadataService;
}
[DisableConcurrentExecution(timeoutInSeconds: 5)]
//[DisableConcurrentExecution(timeoutInSeconds: 5)]
[AutomaticRetry(Attempts = 0, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public void ScanLibraries()
{
@ -64,7 +64,7 @@ namespace API.Services.Tasks
_scannedSeries = null;
}
[DisableConcurrentExecution(5)]
//[DisableConcurrentExecution(5)]
[AutomaticRetry(Attempts = 0, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public void ScanLibrary(int libraryId, bool forceUpdate)
{

View File

@ -18,14 +18,13 @@ namespace API.Services
_provider = provider;
}
public Task ExecuteAsync(CancellationToken cancellationToken)
public Task ExecuteAsync(CancellationToken cancellationToken = default)
{
using (var scope = _provider.CreateScope())
using var scope = _provider.CreateScope();
foreach (var singleton in GetServices(_services))
{
foreach (var singleton in GetServices(_services))
{
scope.ServiceProvider.GetServices(singleton);
}
Console.WriteLine("DI preloading of " + singleton.FullName);
scope.ServiceProvider.GetServices(singleton);
}
return Task.CompletedTask;

View File

@ -64,10 +64,9 @@ namespace API
services.AddResponseCaching();
services
.AddStartupTask<WarmupServicesStartupTask>()
.TryAddSingleton(services);
// services
// .AddStartupTask<WarmupServicesStartupTask>()
// //.TryAddSingleton(services);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@ -134,7 +133,7 @@ namespace API
{
Console.WriteLine("Server is shutting down. Going to dispose Hangfire");
//this code is called when the application stops
//TaskScheduler.Client.Dispose();
TaskScheduler.Client.Dispose();
System.Threading.Thread.Sleep(1000);
}
}