Merge branch 'feat/235-s4-trakt' into feat/235-async-contract

This commit is contained in:
2026-07-11 18:02:58 +02:00
2 changed files with 119 additions and 0 deletions
+18
View File
@@ -9,6 +9,7 @@ using ErsatzTV.Application.MediaCollections;
using ErsatzTV.Application.Playouts;
using ErsatzTV.Application.Subtitles;
using ErsatzTV.Core;
using ErsatzTV.Core.Interfaces.Locking;
using MediatR;
namespace ErsatzTV.Services;
@@ -16,16 +17,19 @@ namespace ErsatzTV.Services;
public class WorkerService : BackgroundService
{
private readonly ChannelReader<IBackgroundServiceRequest> _channel;
private readonly IEntityLocker _entityLocker;
private readonly ILogger<WorkerService> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public WorkerService(
ChannelReader<IBackgroundServiceRequest> channel,
IServiceScopeFactory serviceScopeFactory,
IEntityLocker entityLocker,
ILogger<WorkerService> logger)
{
_channel = channel;
_serviceScopeFactory = serviceScopeFactory;
_entityLocker = entityLocker;
_logger = logger;
}
@@ -143,5 +147,19 @@ public class WorkerService : BackgroundService
{
_logger.LogInformation("Worker service shutting down");
}
finally
{
// The global Trakt lock is acquired by SchedulerService/TraktController and released only
// when the *terminal* (Unlock: true) message of a batch is processed here. If this loop
// stops before reaching that message - shutdown break above, channel completion, or the
// reader throwing on cancellation - the release never fires and the in-memory Trakt lock
// leaks for the remaining life of the process (subsequent Trakt operations 409 forever).
// Make the batch-release loss-tolerant with a compensating release on worker shutdown.
if (_entityLocker.IsTraktLocked())
{
_logger.LogDebug("Releasing held Trakt lock during worker shutdown");
_entityLocker.UnlockTrakt();
}
}
}
}