Added Status refreshes to Download Monitoring Service and allow DownloadService to report success (but not failure).
This commit is contained in:
parent
f335cc1af8
commit
4e10d30cf6
|
@ -57,13 +57,6 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
||||||
{
|
{
|
||||||
Subject.Check().ShouldBeOk();
|
Subject.Check().ShouldBeOk();
|
||||||
}
|
}
|
||||||
[Test]
|
|
||||||
public void should_not_return_error_when_indexer_failed_less_than_an_hour()
|
|
||||||
{
|
|
||||||
GivenIndexer(1, 0.1, 0.5);
|
|
||||||
|
|
||||||
Subject.Check().ShouldBeOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_warning_if_indexer_unavailable()
|
public void should_return_warning_if_indexer_unavailable()
|
||||||
|
|
|
@ -41,21 +41,6 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||||
.Verify(v => v.Upsert(It.IsAny<IndexerStatus>()), Times.Never());
|
.Verify(v => v.Upsert(It.IsAny<IndexerStatus>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_start_backoff_on_first_failure()
|
|
||||||
{
|
|
||||||
WithStatus(new IndexerStatus());
|
|
||||||
|
|
||||||
Subject.RecordFailure(1);
|
|
||||||
|
|
||||||
VerifyUpdate();
|
|
||||||
|
|
||||||
var status = Subject.GetBlockedProviders().FirstOrDefault();
|
|
||||||
status.Should().NotBeNull();
|
|
||||||
status.DisabledTill.Should().HaveValue();
|
|
||||||
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_cancel_backoff_on_success()
|
public void should_cancel_backoff_on_success()
|
||||||
{
|
{
|
||||||
|
@ -78,20 +63,5 @@ namespace NzbDrone.Core.Test.IndexerTests
|
||||||
|
|
||||||
VerifyNoUpdate();
|
VerifyNoUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_preserve_escalation_on_intermittent_success()
|
|
||||||
{
|
|
||||||
WithStatus(new IndexerStatus { MostRecentFailure = _epoch - TimeSpan.FromSeconds(4), EscalationLevel = 3 });
|
|
||||||
|
|
||||||
Subject.RecordSuccess(1);
|
|
||||||
Subject.RecordSuccess(1);
|
|
||||||
Subject.RecordFailure(1);
|
|
||||||
|
|
||||||
var status = Subject.GetBlockedProviders().FirstOrDefault();
|
|
||||||
status.Should().NotBeNull();
|
|
||||||
status.DisabledTill.Should().HaveValue();
|
|
||||||
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Composition;
|
using NzbDrone.Common.Composition;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
@ -9,17 +11,24 @@ namespace NzbDrone.Core.Download
|
||||||
{
|
{
|
||||||
public interface IDownloadClientFactory : IProviderFactory<IDownloadClient, DownloadClientDefinition>
|
public interface IDownloadClientFactory : IProviderFactory<IDownloadClient, DownloadClientDefinition>
|
||||||
{
|
{
|
||||||
|
List<IDownloadClient> DownloadHandlingEnabled(bool filterBlockedClients = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DownloadClientFactory : ProviderFactory<IDownloadClient, DownloadClientDefinition>, IDownloadClientFactory
|
public class DownloadClientFactory : ProviderFactory<IDownloadClient, DownloadClientDefinition>, IDownloadClientFactory
|
||||||
{
|
{
|
||||||
private readonly IDownloadClientRepository _providerRepository;
|
private readonly IDownloadClientStatusService _downloadClientStatusService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public DownloadClientFactory(IDownloadClientRepository providerRepository, IEnumerable<IDownloadClient> providers, IContainer container, IEventAggregator eventAggregator, Logger logger)
|
public DownloadClientFactory(IDownloadClientStatusService downloadClientStatusService,
|
||||||
|
IDownloadClientRepository providerRepository,
|
||||||
|
IEnumerable<IDownloadClient> providers,
|
||||||
|
IContainer container,
|
||||||
|
IEventAggregator eventAggregator,
|
||||||
|
Logger logger)
|
||||||
: base(providerRepository, providers, container, eventAggregator, logger)
|
: base(providerRepository, providers, container, eventAggregator, logger)
|
||||||
{
|
{
|
||||||
_providerRepository = providerRepository;
|
_downloadClientStatusService = downloadClientStatusService;
|
||||||
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override List<DownloadClientDefinition> Active()
|
protected override List<DownloadClientDefinition> Active()
|
||||||
|
@ -33,5 +42,46 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
definition.Protocol = provider.Protocol;
|
definition.Protocol = provider.Protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<IDownloadClient> DownloadHandlingEnabled(bool filterBlockedClients = true)
|
||||||
|
{
|
||||||
|
var enabledClients = GetAvailableProviders();
|
||||||
|
|
||||||
|
if (filterBlockedClients)
|
||||||
|
{
|
||||||
|
return FilterBlockedClients(enabledClients).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return enabledClients.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IDownloadClient> FilterBlockedClients(IEnumerable<IDownloadClient> clients)
|
||||||
|
{
|
||||||
|
var blockedIndexers = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
|
||||||
|
|
||||||
|
foreach (var client in clients)
|
||||||
|
{
|
||||||
|
DownloadClientStatus downloadClientStatus;
|
||||||
|
if (blockedIndexers.TryGetValue(client.Definition.Id, out downloadClientStatus))
|
||||||
|
{
|
||||||
|
_logger.Debug("Temporarily ignoring download client {0} till {1} due to recent failures.", client.Definition.Name, downloadClientStatus.DisabledTill.Value.ToLocalTime());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValidationResult Test(DownloadClientDefinition definition)
|
||||||
|
{
|
||||||
|
var result = base.Test(definition);
|
||||||
|
|
||||||
|
if (result == null && definition.Id != 0)
|
||||||
|
{
|
||||||
|
_downloadClientStatusService.RecordSuccess(definition.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,19 +27,12 @@ namespace NzbDrone.Core.Download
|
||||||
|
|
||||||
public IEnumerable<IDownloadClient> GetDownloadClients()
|
public IEnumerable<IDownloadClient> GetDownloadClients()
|
||||||
{
|
{
|
||||||
return _downloadClientFactory.GetAvailableProviders();//.Select(MapDownloadClient);
|
return _downloadClientFactory.GetAvailableProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDownloadClient Get(int id)
|
public IDownloadClient Get(int id)
|
||||||
{
|
{
|
||||||
return _downloadClientFactory.GetAvailableProviders().Single(d => d.Definition.Id == id);
|
return _downloadClientFactory.GetAvailableProviders().Single(d => d.Definition.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDownloadClient MapDownloadClient(IDownloadClient downloadClient)
|
|
||||||
{
|
|
||||||
_downloadClientFactory.SetProviderCharacteristics(downloadClient, (DownloadClientDefinition)downloadClient.Definition);
|
|
||||||
|
|
||||||
return downloadClient;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,18 +21,21 @@ namespace NzbDrone.Core.Download
|
||||||
public class DownloadService : IDownloadService
|
public class DownloadService : IDownloadService
|
||||||
{
|
{
|
||||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||||
|
private readonly IDownloadClientStatusService _downloadClientStatusService;
|
||||||
private readonly IIndexerStatusService _indexerStatusService;
|
private readonly IIndexerStatusService _indexerStatusService;
|
||||||
private readonly IRateLimitService _rateLimitService;
|
private readonly IRateLimitService _rateLimitService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public DownloadService(IProvideDownloadClient downloadClientProvider,
|
public DownloadService(IProvideDownloadClient downloadClientProvider,
|
||||||
|
IDownloadClientStatusService downloadClientStatusService,
|
||||||
IIndexerStatusService indexerStatusService,
|
IIndexerStatusService indexerStatusService,
|
||||||
IRateLimitService rateLimitService,
|
IRateLimitService rateLimitService,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_downloadClientProvider = downloadClientProvider;
|
_downloadClientProvider = downloadClientProvider;
|
||||||
|
_downloadClientStatusService = downloadClientStatusService;
|
||||||
_indexerStatusService = indexerStatusService;
|
_indexerStatusService = indexerStatusService;
|
||||||
_rateLimitService = rateLimitService;
|
_rateLimitService = rateLimitService;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
|
@ -64,6 +67,7 @@ namespace NzbDrone.Core.Download
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
downloadClientId = downloadClient.Download(remoteEpisode);
|
downloadClientId = downloadClient.Download(remoteEpisode);
|
||||||
|
_downloadClientStatusService.RecordSuccess(downloadClient.Definition.Id);
|
||||||
_indexerStatusService.RecordSuccess(remoteEpisode.Release.IndexerId);
|
_indexerStatusService.RecordSuccess(remoteEpisode.Release.IndexerId);
|
||||||
}
|
}
|
||||||
catch (ReleaseDownloadException ex)
|
catch (ReleaseDownloadException ex)
|
||||||
|
|
|
@ -15,7 +15,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
IHandle<EpisodeGrabbedEvent>,
|
IHandle<EpisodeGrabbedEvent>,
|
||||||
IHandle<EpisodeImportedEvent>
|
IHandle<EpisodeImportedEvent>
|
||||||
{
|
{
|
||||||
private readonly IProvideDownloadClient _downloadClientProvider;
|
private readonly IDownloadClientStatusService _downloadClientStatusService;
|
||||||
|
private readonly IDownloadClientFactory _downloadClientFactory;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IManageCommandQueue _manageCommandQueue;
|
private readonly IManageCommandQueue _manageCommandQueue;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
|
@ -25,7 +26,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
private readonly Debouncer _refreshDebounce;
|
private readonly Debouncer _refreshDebounce;
|
||||||
|
|
||||||
public DownloadMonitoringService(IProvideDownloadClient downloadClientProvider,
|
public DownloadMonitoringService(IDownloadClientStatusService downloadClientStatusService,
|
||||||
|
IDownloadClientFactory downloadClientFactory,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
IManageCommandQueue manageCommandQueue,
|
IManageCommandQueue manageCommandQueue,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
|
@ -34,7 +36,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
ITrackedDownloadService trackedDownloadService,
|
ITrackedDownloadService trackedDownloadService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_downloadClientProvider = downloadClientProvider;
|
_downloadClientStatusService = downloadClientStatusService;
|
||||||
|
_downloadClientFactory = downloadClientFactory;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_manageCommandQueue = manageCommandQueue;
|
_manageCommandQueue = manageCommandQueue;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
|
@ -56,7 +59,7 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
_refreshDebounce.Pause();
|
_refreshDebounce.Pause();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var downloadClients = _downloadClientProvider.GetDownloadClients();
|
var downloadClients = _downloadClientFactory.DownloadHandlingEnabled();
|
||||||
|
|
||||||
var trackedDownloads = new List<TrackedDownload>();
|
var trackedDownloads = new List<TrackedDownload>();
|
||||||
|
|
||||||
|
@ -84,9 +87,12 @@ namespace NzbDrone.Core.Download.TrackedDownloads
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
downloadClientHistory = downloadClient.GetItems().ToList();
|
downloadClientHistory = downloadClient.GetItems().ToList();
|
||||||
|
|
||||||
|
_downloadClientStatusService.RecordSuccess(downloadClient.Definition.Id);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_downloadClientStatusService.RecordFailure(downloadClient.Definition.Id);
|
||||||
_logger.Warn(ex, "Unable to retrieve queue and history items from " + downloadClient.Definition.Name);
|
_logger.Warn(ex, "Unable to retrieve queue and history items from " + downloadClient.Definition.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
_logger.Debug(ex, "Unable to communicate with {0}", downloadClient.Definition.Name);
|
_logger.Debug(ex, "Unable to communicate with {0}", downloadClient.Definition.Name);
|
||||||
|
|
||||||
var message = $"Unable to communicate with {downloadClient.Definition.Name}.";
|
var message = $"Unable to communicate with {downloadClient.Definition.Name}.";
|
||||||
return new HealthCheck(GetType(), HealthCheckResult.Error, $"{message} {ex.Message}");
|
return new HealthCheck(GetType(), HealthCheckResult.Error, $"{message} {ex.Message}", "#unable-to-communicate-with-download-client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
i => i.Definition.Id,
|
i => i.Definition.Id,
|
||||||
s => s.ProviderId,
|
s => s.ProviderId,
|
||||||
(i, s) => new { Provider = i, Status = s })
|
(i, s) => new { Provider = i, Status = s })
|
||||||
.Where(v => (v.Status.MostRecentFailure - v.Status.InitialFailure) > TimeSpan.FromHours(1))
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (backOffProviders.Empty())
|
if (backOffProviders.Empty())
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
Status = v.GetStatus()
|
Status = v.GetStatus()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
catch (DownloadClientException)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// One or more download clients failed, assume the health is okay and verify later
|
// One or more download clients failed, assume the health is okay and verify later
|
||||||
return new HealthCheck(GetType());
|
return new HealthCheck(GetType());
|
||||||
|
|
|
@ -23,7 +23,6 @@ namespace NzbDrone.Core.HealthCheck.Checks
|
||||||
i => i.Definition.Id,
|
i => i.Definition.Id,
|
||||||
s => s.ProviderId,
|
s => s.ProviderId,
|
||||||
(i, s) => new { Provider = i, Status = s })
|
(i, s) => new { Provider = i, Status = s })
|
||||||
.Where(v => (v.Status.MostRecentFailure - v.Status.InitialFailure) > TimeSpan.FromHours(1))
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (backOffProviders.Empty())
|
if (backOffProviders.Empty())
|
||||||
|
|
Loading…
Reference in New Issue