1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-04 10:02:40 +01:00

New: Differentiate between short term and long term (more than 6 hours) indexer failures (#5202)

* New: Differentiate between short term and long term (more than 6 hours) indexer failures

(cherry picked from commit 2adedb97da5ad31b65f0dc2eec5c263efe95731f)

* fixup! Mock Localization

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
Co-authored-by: Qstick <qstick@gmail.com>
This commit is contained in:
servarr[bot] 2020-10-15 07:20:02 -04:00 committed by GitHub
parent 27354507cb
commit f2f26d88b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 173 additions and 10 deletions

View File

@ -19,6 +19,7 @@ function getInternalLink(source) {
case 'IndexerRssCheck': case 'IndexerRssCheck':
case 'IndexerSearchCheck': case 'IndexerSearchCheck':
case 'IndexerStatusCheck': case 'IndexerStatusCheck':
case 'IndexerLongTermStatusCheck':
return ( return (
<IconButton <IconButton
name={icons.SETTINGS} name={icons.SETTINGS}

View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.HealthCheck.Checks;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.HealthCheck.Checks
{
[TestFixture]
public class IndexerLongTermStatusCheckFixture : CoreTest<IndexerLongTermStatusCheck>
{
private List<IIndexer> _indexers = new List<IIndexer>();
private List<IndexerStatus> _blockedIndexers = new List<IndexerStatus>();
[SetUp]
public void SetUp()
{
Mocker.GetMock<IIndexerFactory>()
.Setup(v => v.GetAvailableProviders())
.Returns(_indexers);
Mocker.GetMock<IIndexerStatusService>()
.Setup(v => v.GetBlockedProviders())
.Returns(_blockedIndexers);
Mocker.GetMock<ILocalizationService>()
.Setup(v => v.GetLocalizedString(It.IsAny<string>()))
.Returns("Error");
}
private Mock<IIndexer> GivenIndexer(int id, double backoffHours, double failureHours)
{
var mockIndexer = new Mock<IIndexer>();
mockIndexer.SetupGet(s => s.Definition).Returns(new IndexerDefinition { Id = id });
mockIndexer.SetupGet(s => s.SupportsSearch).Returns(true);
_indexers.Add(mockIndexer.Object);
if (backoffHours != 0.0)
{
_blockedIndexers.Add(new IndexerStatus
{
ProviderId = id,
InitialFailure = DateTime.UtcNow.AddHours(-failureHours),
MostRecentFailure = DateTime.UtcNow.AddHours(-0.1),
EscalationLevel = 5,
DisabledTill = DateTime.UtcNow.AddHours(backoffHours)
});
}
return mockIndexer;
}
[Test]
public void should_not_return_error_when_no_indexers()
{
Subject.Check().ShouldBeOk();
}
[Test]
public void should_return_warning_if_indexer_unavailable()
{
GivenIndexer(1, 10.0, 24.0);
GivenIndexer(2, 0.0, 0.0);
Subject.Check().ShouldBeWarning();
}
[Test]
public void should_return_error_if_all_indexers_unavailable()
{
GivenIndexer(1, 10.0, 24.0);
Subject.Check().ShouldBeError();
}
[Test]
public void should_return_warning_if_few_indexers_unavailable()
{
GivenIndexer(1, 10.0, 24.0);
GivenIndexer(2, 10.0, 24.0);
GivenIndexer(3, 0.0, 0.0);
Subject.Check().ShouldBeWarning();
}
}
}

View File

@ -65,7 +65,7 @@ public void should_not_return_error_when_no_indexers()
[Test] [Test]
public void should_return_warning_if_indexer_unavailable() public void should_return_warning_if_indexer_unavailable()
{ {
GivenIndexer(1, 10.0, 24.0); GivenIndexer(1, 2.0, 4.0);
GivenIndexer(2, 0.0, 0.0); GivenIndexer(2, 0.0, 0.0);
Subject.Check().ShouldBeWarning(); Subject.Check().ShouldBeWarning();
@ -74,7 +74,7 @@ public void should_return_warning_if_indexer_unavailable()
[Test] [Test]
public void should_return_error_if_all_indexers_unavailable() public void should_return_error_if_all_indexers_unavailable()
{ {
GivenIndexer(1, 10.0, 24.0); GivenIndexer(1, 2.0, 4.0);
Subject.Check().ShouldBeError(); Subject.Check().ShouldBeError();
} }
@ -82,8 +82,8 @@ public void should_return_error_if_all_indexers_unavailable()
[Test] [Test]
public void should_return_warning_if_few_indexers_unavailable() public void should_return_warning_if_few_indexers_unavailable()
{ {
GivenIndexer(1, 10.0, 24.0); GivenIndexer(1, 2.0, 4.0);
GivenIndexer(2, 10.0, 24.0); GivenIndexer(2, 2.0, 4.0);
GivenIndexer(3, 0.0, 0.0); GivenIndexer(3, 0.0, 0.0);
Subject.Check().ShouldBeWarning(); Subject.Check().ShouldBeWarning();

View File

@ -0,0 +1,59 @@
using System;
using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Localization;
using NzbDrone.Core.ThingiProvider.Events;
namespace NzbDrone.Core.HealthCheck.Checks
{
[CheckOn(typeof(ProviderUpdatedEvent<IIndexer>))]
[CheckOn(typeof(ProviderDeletedEvent<IIndexer>))]
[CheckOn(typeof(ProviderStatusChangedEvent<IIndexer>))]
public class IndexerLongTermStatusCheck : HealthCheckBase
{
private readonly IIndexerFactory _providerFactory;
private readonly IIndexerStatusService _providerStatusService;
public IndexerLongTermStatusCheck(IIndexerFactory providerFactory,
IIndexerStatusService providerStatusService,
ILocalizationService localizationService)
: base(localizationService)
{
_providerFactory = providerFactory;
_providerStatusService = providerStatusService;
}
public override HealthCheck Check()
{
var enabledProviders = _providerFactory.GetAvailableProviders();
var backOffProviders = enabledProviders.Join(_providerStatusService.GetBlockedProviders(),
i => i.Definition.Id,
s => s.ProviderId,
(i, s) => new { Provider = i, Status = s })
.Where(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.Before(
DateTime.UtcNow.AddHours(-6)))
.ToList();
if (backOffProviders.Empty())
{
return new HealthCheck(GetType());
}
if (backOffProviders.Count == enabledProviders.Count)
{
return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerLongTermStatusCheckAllClientMessage"),
"#indexers-are-unavailable-due-to-failures");
}
return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerLongTermStatusCheckSingleClientMessage"),
string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
"#indexers-are-unavailable-due-to-failures");
}
}
}

View File

@ -1,3 +1,4 @@
using System;
using System.Linq; using System.Linq;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
@ -28,6 +29,9 @@ public override HealthCheck Check()
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(p => p.Status.InitialFailure.HasValue &&
p.Status.InitialFailure.Value.After(
DateTime.UtcNow.AddHours(-6)))
.ToList(); .ToList();
if (backOffProviders.Empty()) if (backOffProviders.Empty())
@ -37,10 +41,17 @@ public override HealthCheck Check()
if (backOffProviders.Count == enabledProviders.Count) if (backOffProviders.Count == enabledProviders.Count)
{ {
return new HealthCheck(GetType(), HealthCheckResult.Error, _localizationService.GetLocalizedString("IndexerStatusCheckAllClientMessage"), "#indexers-are-unavailable-due-to-failures"); return new HealthCheck(GetType(),
HealthCheckResult.Error,
_localizationService.GetLocalizedString("IndexerStatusCheckAllClientMessage"),
"#indexers-are-unavailable-due-to-failures");
} }
return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format(_localizationService.GetLocalizedString("IndexerStatusCheckSingleClientMessage"), string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))), "#indexers-are-unavailable-due-to-failures"); return new HealthCheck(GetType(),
HealthCheckResult.Warning,
string.Format(_localizationService.GetLocalizedString("IndexerStatusCheckSingleClientMessage"),
string.Join(", ", backOffProviders.Select(v => v.Provider.Definition.Name))),
"#indexers-are-unavailable-due-to-failures");
} }
} }
} }

View File

@ -343,6 +343,8 @@
"IndexersSettingsSummary": "Indexers and release restrictions", "IndexersSettingsSummary": "Indexers and release restrictions",
"IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures", "IndexerStatusCheckAllClientMessage": "All indexers are unavailable due to failures",
"IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}", "IndexerStatusCheckSingleClientMessage": "Indexers unavailable due to failures: {0}",
"IndexerLongTermStatusCheckAllClientMessage": "All indexers are unavailable due to failures for more than 6 hours",
"IndexerLongTermStatusCheckSingleClientMessage": "Indexers unavailable due to failures for more than 6 hours: {0}",
"Info": "Info", "Info": "Info",
"InteractiveImport": "Interactive Import", "InteractiveImport": "Interactive Import",
"InteractiveSearch": "Interactive Search", "InteractiveSearch": "Interactive Search",