passed WebhookScanTarget to ScheduleMalwareBlockerWebhookRetry instead of individual fields

This commit is contained in:
Flaminel
2026-06-16 23:19:58 +03:00
parent a34a3d3c7e
commit 614e97313e
4 changed files with 21 additions and 25 deletions

View File

@@ -5,6 +5,7 @@ using Cleanuparr.Infrastructure.Features.Arr;
using Cleanuparr.Infrastructure.Features.Arr.Interfaces;
using Cleanuparr.Infrastructure.Features.DownloadClient;
using Cleanuparr.Infrastructure.Features.DownloadRemover.Models;
using Cleanuparr.Infrastructure.Features.Jobs;
using Cleanuparr.Infrastructure.Features.MalwareBlocker;
using Cleanuparr.Infrastructure.Tests.Features.Jobs.TestHelpers;
using Cleanuparr.Infrastructure.Tests.TestHelpers;
@@ -417,8 +418,8 @@ public class MalwareBlockerTests : IDisposable
await mockDownloadService.Received(1).BlockUnwantedFilesAsync("match-hash", Arg.Any<List<string>>());
await mockDownloadService.DidNotReceive().BlockUnwantedFilesAsync("other-hash", Arg.Any<List<string>>());
// Found in a client -> resolved, no retry scheduled
await _fixture.JobManagementService.DidNotReceive().ScheduleMalwareBlockerWebhookRetry(
Arg.Any<Guid>(), Arg.Any<string>(), Arg.Any<long>(), Arg.Any<InstanceType>(), Arg.Any<int>());
await _fixture.JobManagementService.DidNotReceive()
.ScheduleMalwareBlockerWebhookRetry(Arg.Any<WebhookScanTarget>());
}
[Fact]
@@ -468,7 +469,12 @@ public class MalwareBlockerTests : IDisposable
// Assert
await _fixture.JobManagementService.Received(1).ScheduleMalwareBlockerWebhookRetry(
sonarrInstance.Id, "pending-hash", 7, InstanceType.Sonarr, 1);
Arg.Is<WebhookScanTarget>(t =>
t.InstanceId == sonarrInstance.Id &&
t.DownloadId == "pending-hash" &&
t.ContentId == 7 &&
t.Type == InstanceType.Sonarr &&
t.RetryIndex == 1));
}
[Fact]
@@ -513,8 +519,8 @@ public class MalwareBlockerTests : IDisposable
// Assert: usenet is acknowledged once seen in the queue -> no scan, no retry
await mockDownloadService.DidNotReceive().BlockUnwantedFilesAsync(Arg.Any<string>(), Arg.Any<List<string>>());
await _fixture.JobManagementService.DidNotReceive().ScheduleMalwareBlockerWebhookRetry(
Arg.Any<Guid>(), Arg.Any<string>(), Arg.Any<long>(), Arg.Any<InstanceType>(), Arg.Any<int>());
await _fixture.JobManagementService.DidNotReceive()
.ScheduleMalwareBlockerWebhookRetry(Arg.Any<WebhookScanTarget>());
}
[Fact]

View File

@@ -139,20 +139,12 @@ public sealed class MalwareBlocker : GenericHandler
if (!resolved)
{
await _jobManagementService.ScheduleMalwareBlockerWebhookRetry(
target.InstanceId, target.DownloadId, target.ContentId, target.Type, target.RetryIndex);
await _jobManagementService.ScheduleMalwareBlockerWebhookRetry(target);
}
}
protected override Task ProcessInstanceAsync(ArrInstance instance) => ScanInstanceAsync(instance);
/// <summary>
/// Iterates the instance queue and scans each download. When <paramref name="target"/> is set, only
/// the matching download is processed and the return value reports whether it was resolved (found and
/// scanned, a usenet record, or deliberately skipped); <c>false</c> means it was not yet found in any
/// download client and the webhook scan should be retried. For full scans (no target) the return
/// value is always <c>false</c> and ignored.
/// </summary>
private async Task<bool> ScanInstanceAsync(ArrInstance instance, WebhookScanTarget? target = null)
{
List<string> ignoredDownloads = ContextProvider.Get<GeneralConfig>(nameof(GeneralConfig)).IgnoredDownloads;

View File

@@ -1,4 +1,5 @@
using Cleanuparr.Domain.Enums;
using Cleanuparr.Infrastructure.Features.Jobs;
using Cleanuparr.Infrastructure.Models;
using Quartz;
@@ -11,18 +12,15 @@ public interface IJobManagementService
Task<bool> TriggerJobOnce(JobType jobType);
/// <summary>
/// Schedules the first targeted MalwareBlocker scan for a single download received via an *arr
/// "On Grab" webhook, on the dedicated webhook JobKey (independent of the scheduled MalwareBlocker
/// job). Subsequent retries are scheduled by the handler via
/// <see cref="ScheduleMalwareBlockerWebhookRetry"/> only while the download has not been found.
/// Schedules the first targeted MalwareBlocker scan for a single download received via an *arr "On Grab" webhook.
/// Subsequent retries are scheduled by the handler via <see cref="ScheduleMalwareBlockerWebhookRetry"/> only while the download has not been found.
/// </summary>
Task<bool> TriggerMalwareBlockerWebhook(Guid instanceId, string downloadId, long contentId, InstanceType type);
/// <summary>
/// Schedules the next targeted MalwareBlocker webhook scan after a completed attempt that did not
/// find the download, using the configured retry delays. No-op once the delays are exhausted.
/// Schedules the next targeted MalwareBlocker webhook scan after a completed attempt.
/// </summary>
Task<bool> ScheduleMalwareBlockerWebhookRetry(Guid instanceId, string downloadId, long contentId, InstanceType type, int completedIndex);
Task<bool> ScheduleMalwareBlockerWebhookRetry(WebhookScanTarget target);
Task<IReadOnlyList<JobInfo>> GetAllJobs(IScheduler? scheduler = null);
Task<JobInfo> GetJob(JobType jobType);

View File

@@ -377,19 +377,19 @@ public class JobManagementService : IJobManagementService
return ScheduleWebhookAttempt(instanceId, downloadId, contentId, type, attemptIndex: 0);
}
public Task<bool> ScheduleMalwareBlockerWebhookRetry(Guid instanceId, string downloadId, long contentId, InstanceType type, int completedIndex)
public Task<bool> ScheduleMalwareBlockerWebhookRetry(WebhookScanTarget target)
{
int nextIndex = completedIndex + 1;
int nextIndex = target.RetryIndex + 1;
if (nextIndex >= Constants.MalwareBlockerWebhookRetryDelays.Count)
{
_logger.LogDebug(
"MalwareBlocker webhook scan gave up for download {downloadId} on {type} instance {instanceId} after {attempts} attempts",
downloadId, type, instanceId, Constants.MalwareBlockerWebhookRetryDelays.Count);
target.DownloadId, target.Type, target.InstanceId, Constants.MalwareBlockerWebhookRetryDelays.Count);
return Task.FromResult(false);
}
return ScheduleWebhookAttempt(instanceId, downloadId, contentId, type, nextIndex);
return ScheduleWebhookAttempt(target.InstanceId, target.DownloadId, target.ContentId, target.Type, nextIndex);
}
private async Task<bool> ScheduleWebhookAttempt(Guid instanceId, string downloadId, long contentId, InstanceType type, int attemptIndex)