From 84bbb8ca83ecf57daae68788c9b7128075bddac7 Mon Sep 17 00:00:00 2001 From: Daniel Marbach Date: Thu, 21 Mar 2024 15:48:16 +0100 Subject: [PATCH 01/14] Align MinimumStorageRequiredForIngestion --- ...heckMinimumStorageRequiredForIngestion.cs} | 29 ++++++------------- .../MinimumRequiredStorageState.cs | 7 +++++ .../RavenPersistence.cs | 2 +- .../UnitOfWork/RavenAuditUnitOfWorkFactory.cs | 27 +++++------------ ...CheckMinimumStorageRequiredForIngestion.cs | 20 ++++--------- 5 files changed, 29 insertions(+), 56 deletions(-) rename src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/{CheckMinimumStorageRequiredForAuditIngestion.cs => CheckMinimumStorageRequiredForIngestion.cs} (69%) create mode 100644 src/ServiceControl.Audit.Persistence.RavenDB/MinimumRequiredStorageState.cs diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForAuditIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs similarity index 69% rename from src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForAuditIngestion.cs rename to src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 66ab8b5209..93c6cea29f 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForAuditIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -6,17 +6,13 @@ using System.Threading.Tasks; using NServiceBus.CustomChecks; using NServiceBus.Logging; - using ServiceControl.Audit.Persistence.RavenDB; + using RavenDB; - class CheckMinimumStorageRequiredForAuditIngestion : CustomCheck + class CheckMinimumStorageRequiredForIngestion( + MinimumRequiredStorageState stateHolder, + DatabaseConfiguration databaseConfiguration) + : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { - public CheckMinimumStorageRequiredForAuditIngestion(State stateHolder, DatabaseConfiguration databaseConfiguration) - : base("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) - { - this.stateHolder = stateHolder; - this.databaseConfiguration = databaseConfiguration; - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; @@ -25,7 +21,7 @@ public override Task PerformCheck(CancellationToken cancellationTok if (dataPathRoot == null) { stateHolder.CanIngestMore = true; - return successResult; + return SuccessResult; } Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); @@ -44,7 +40,7 @@ public override Task PerformCheck(CancellationToken cancellationTok if (percentRemaining > percentageThreshold) { stateHolder.CanIngestMore = true; - return successResult; + return SuccessResult; } var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; @@ -53,14 +49,7 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Failed(message); } - readonly State stateHolder; - readonly DatabaseConfiguration databaseConfiguration; - static Task successResult = Task.FromResult(CheckResult.Pass); - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForAuditIngestion)); - - public class State - { - public bool CanIngestMore { get; set; } = true; - } + static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); + static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/MinimumRequiredStorageState.cs b/src/ServiceControl.Audit.Persistence.RavenDB/MinimumRequiredStorageState.cs new file mode 100644 index 0000000000..5259d8f0ca --- /dev/null +++ b/src/ServiceControl.Audit.Persistence.RavenDB/MinimumRequiredStorageState.cs @@ -0,0 +1,7 @@ +namespace ServiceControl.Audit.Persistence.RavenDB +{ + public class MinimumRequiredStorageState + { + public bool CanIngestMore { get; set; } = true; + } +} \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs index 6f416fe8ca..2c92f4f07e 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs @@ -14,7 +14,7 @@ public void AddPersistence(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } public void AddInstaller(IServiceCollection services) => ConfigureLifecycle(services, databaseConfiguration); diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/UnitOfWork/RavenAuditUnitOfWorkFactory.cs b/src/ServiceControl.Audit.Persistence.RavenDB/UnitOfWork/RavenAuditUnitOfWorkFactory.cs index b404ac935d..738c4a42ba 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/UnitOfWork/RavenAuditUnitOfWorkFactory.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/UnitOfWork/RavenAuditUnitOfWorkFactory.cs @@ -5,19 +5,14 @@ using Persistence.UnitOfWork; using Raven.Client.Documents.BulkInsert; using RavenDB; - using ServiceControl.Audit.Persistence.RavenDB.CustomChecks; - class RavenAuditIngestionUnitOfWorkFactory : IAuditIngestionUnitOfWorkFactory + class RavenAuditIngestionUnitOfWorkFactory( + IRavenDocumentStoreProvider documentStoreProvider, + IRavenSessionProvider sessionProvider, + DatabaseConfiguration databaseConfiguration, + MinimumRequiredStorageState customCheckState) + : IAuditIngestionUnitOfWorkFactory { - public RavenAuditIngestionUnitOfWorkFactory(IRavenDocumentStoreProvider documentStoreProvider, IRavenSessionProvider sessionProvider, - DatabaseConfiguration databaseConfiguration, CheckMinimumStorageRequiredForAuditIngestion.State customCheckState) - { - this.documentStoreProvider = documentStoreProvider; - this.sessionProvider = sessionProvider; - this.databaseConfiguration = databaseConfiguration; - this.customCheckState = customCheckState; - } - public IAuditIngestionUnitOfWork StartNew(int batchSize) { var timedCancellationSource = new CancellationTokenSource(databaseConfiguration.BulkInsertCommitTimeout); @@ -29,14 +24,6 @@ public IAuditIngestionUnitOfWork StartNew(int batchSize) ); } - public bool CanIngestMore() - { - return customCheckState.CanIngestMore; - } - - readonly IRavenDocumentStoreProvider documentStoreProvider; - readonly IRavenSessionProvider sessionProvider; - readonly DatabaseConfiguration databaseConfiguration; - readonly CheckMinimumStorageRequiredForAuditIngestion.State customCheckState; + public bool CanIngestMore() => customCheckState.CanIngestMore; } } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 9915aa551b..8c75d426b0 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -9,19 +9,11 @@ using Persistence.RavenDB; using ServiceControl.Persistence; - class CheckMinimumStorageRequiredForIngestion : CustomCheck + class CheckMinimumStorageRequiredForIngestion( + MinimumRequiredStorageState stateHolder, + RavenPersisterSettings settings) + : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { - public CheckMinimumStorageRequiredForIngestion( - MinimumRequiredStorageState stateHolder, - RavenPersisterSettings settings) - : base("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) - { - this.stateHolder = stateHolder; - this.settings = settings; - - dataPathRoot = Path.GetPathRoot(settings.DatabasePath); - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; @@ -79,9 +71,7 @@ public static void Validate(RavenPersisterSettings settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - readonly MinimumRequiredStorageState stateHolder; - readonly RavenPersisterSettings settings; - readonly string dataPathRoot; + readonly string dataPathRoot = Path.GetPathRoot(settings.DatabasePath); decimal percentageThreshold; From 5e8fcc190b5d99d99e77d22e7ffb056e823b84b5 Mon Sep 17 00:00:00 2001 From: Daniel Marbach Date: Thu, 21 Mar 2024 15:59:35 +0100 Subject: [PATCH 02/14] Move CheckFreeDiskSpace into persistence layer --- .../CustomChecks/CheckFreeDiskSpace.cs | 50 +++++++++++++++ .../CustomChecks/CheckRavenDBIndexLag.cs | 15 ++--- .../DatabaseConfiguration.cs | 49 ++++++--------- .../Infrastructure/CheckFreeDiskSpace.cs | 62 ------------------- 4 files changed, 73 insertions(+), 103 deletions(-) create mode 100644 src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs delete mode 100644 src/ServiceControl.Audit/Infrastructure/CheckFreeDiskSpace.cs diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs new file mode 100644 index 0000000000..0a34a77e47 --- /dev/null +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -0,0 +1,50 @@ +namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks +{ + using System; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using NServiceBus.CustomChecks; + using NServiceBus.Logging; + using RavenDB; + + class CheckFreeDiskSpace : CustomCheck + { + public CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : base("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) + { + dataPath = databaseConfiguration.ServerConfiguration.DbPath; + percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; + Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); + } + + public override Task PerformCheck(CancellationToken cancellationToken = default) + { + var dataPathRoot = Path.GetPathRoot(dataPath); + + if (dataPathRoot == null) + { + throw new Exception($"Unable to find the root of the data path {dataPath}"); + } + + var dataDriveInfo = new DriveInfo(dataPathRoot); + var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; + var totalSpace = (decimal)dataDriveInfo.TotalSize; + + var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; + + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Free space: {availableFreeSpace:N0}B | Total: {totalSpace:N0}B | Percent remaining {percentRemaining:P1}"); + } + + return percentRemaining > percentageThreshold + ? CheckResult.Pass + : CheckResult.Failed($"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'."); + } + + readonly string dataPath; + readonly decimal percentageThreshold; + + static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); + } +} \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index d56b0b60d2..94eb561d06 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -1,23 +1,18 @@ -namespace ServiceControl +namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks { using System; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; - using Audit.Persistence.RavenDB; using NServiceBus.CustomChecks; using NServiceBus.Logging; using Raven.Client.Documents.Operations; + using ServiceControl.Audit.Persistence.RavenDB; - class CheckRavenDBIndexLag : CustomCheck + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) + : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { - public CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) - : base("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) - { - this.documentStoreProvider = documentStoreProvider; - } - public override async Task PerformCheck(CancellationToken cancellationToken = default) { var store = documentStoreProvider.GetDocumentStore(); @@ -84,7 +79,5 @@ static void CreateDiagnosticsLogEntry(DatabaseStatistics statistics, IndexInform static readonly TimeSpan IndexLagThresholdWarning = TimeSpan.FromMinutes(1); static readonly TimeSpan IndexLagThresholdError = TimeSpan.FromMinutes(10); static readonly ILog Log = LogManager.GetLogger(); - - readonly IRavenDocumentStoreProvider documentStoreProvider; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs index f1cb948d5e..57db7a9af9 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs @@ -3,43 +3,32 @@ using System; using Sparrow.Json; - public class DatabaseConfiguration + public class DatabaseConfiguration( + string name, + int expirationProcessTimerInSeconds, + bool enableFullTextSearch, + TimeSpan auditRetentionPeriod, + int maxBodySizeToStore, + int minimumStorageLeftRequiredForIngestion, + ServerConfiguration serverConfiguration, + TimeSpan bulkInsertCommitTimeout) { - public DatabaseConfiguration(string name, - int expirationProcessTimerInSeconds, - bool enableFullTextSearch, - TimeSpan auditRetentionPeriod, - int maxBodySizeToStore, - int minimumStorageLeftRequiredForIngestion, - ServerConfiguration serverConfiguration, - TimeSpan bulkInsertCommitTimeout) - { - Name = name; - ExpirationProcessTimerInSeconds = expirationProcessTimerInSeconds; - EnableFullTextSearch = enableFullTextSearch; - AuditRetentionPeriod = auditRetentionPeriod; - MaxBodySizeToStore = maxBodySizeToStore; - ServerConfiguration = serverConfiguration; - BulkInsertCommitTimeout = bulkInsertCommitTimeout; - MinimumStorageLeftRequiredForIngestion = minimumStorageLeftRequiredForIngestion; - } - - public string Name { get; } - - public int ExpirationProcessTimerInSeconds { get; } - - public bool EnableFullTextSearch { get; } + public string Name { get; } = name; + + public int ExpirationProcessTimerInSeconds { get; } = expirationProcessTimerInSeconds; + + public bool EnableFullTextSearch { get; } = enableFullTextSearch; public Func FindClrType { get; } - public ServerConfiguration ServerConfiguration { get; } + public ServerConfiguration ServerConfiguration { get; } = serverConfiguration; - public TimeSpan AuditRetentionPeriod { get; } + public TimeSpan AuditRetentionPeriod { get; } = auditRetentionPeriod; - public int MaxBodySizeToStore { get; } + public int MaxBodySizeToStore { get; } = maxBodySizeToStore; - public int MinimumStorageLeftRequiredForIngestion { get; internal set; } //Setting for ATT only + public int MinimumStorageLeftRequiredForIngestion { get; internal set; } = minimumStorageLeftRequiredForIngestion; //Setting for ATT only - public TimeSpan BulkInsertCommitTimeout { get; } + public TimeSpan BulkInsertCommitTimeout { get; } = bulkInsertCommitTimeout; } } diff --git a/src/ServiceControl.Audit/Infrastructure/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit/Infrastructure/CheckFreeDiskSpace.cs deleted file mode 100644 index 61ce8a2a45..0000000000 --- a/src/ServiceControl.Audit/Infrastructure/CheckFreeDiskSpace.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace ServiceControl.Audit.Infrastructure -{ - using System; - using System.IO; - using System.Threading; - using System.Threading.Tasks; - using NServiceBus.CustomChecks; - using NServiceBus.Logging; - using ServiceControl.Configuration; - - class CheckFreeDiskSpace : CustomCheck - { - public CheckFreeDiskSpace(Settings.Settings settings) : base("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) - { - dataPath = SettingsReader.Read(Settings.Settings.SettingsRootNamespace, "DbPath"); - percentageThreshold = settings.DataSpaceRemainingThreshold / 100m; - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); - } - - public override Task PerformCheck(CancellationToken cancellationToken = default) - { - // TODO This custom check is problematic: - // This could be null for the following reasons: - // 1. DbPath is empty because using in-memory - // 2. DbPath is empty because using external RavenDB - // 3. DbPath is empty because using default location - // This should only passing automatically for the first two cases. - // However, there isn't a good way to determine which case we're in with the info this check currently has access to. - if (string.IsNullOrEmpty(dataPath)) - { - return CheckResult.Pass; - } - - var dataPathRoot = Path.GetPathRoot(dataPath) ?? throw new Exception($"Unable to find the root of the data path {dataPath}"); - - var dataDriveInfo = new DriveInfo(dataPathRoot); - var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; - var totalSpace = (decimal)dataDriveInfo.TotalSize; - - var percentRemaining = (decimal)dataDriveInfo.AvailableFreeSpace / dataDriveInfo.TotalSize; - - if (Logger.IsDebugEnabled) - { - Logger.Debug($"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); - } - - if (percentRemaining > percentageThreshold) - { - return CheckResult.Pass; - } - - var message = $"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'."; - - Logger.Warn(message); - return CheckResult.Failed(message); - } - - readonly string dataPath; - decimal percentageThreshold; - static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); - } -} \ No newline at end of file From 5b6b9a707a0c46e0f710539fcfe7cc4c47687408 Mon Sep 17 00:00:00 2001 From: Daniel Marbach Date: Thu, 21 Mar 2024 17:02:12 +0100 Subject: [PATCH 03/14] Align custom checks for ingestion and free space with main instance plus get rid of double validation (things are still messy but better than before) --- .../CustomChecks/CheckFreeDiskSpace.cs | 36 ++++++++++++++++++- ...CheckMinimumStorageRequiredForIngestion.cs | 35 ++++++++++++++++++ .../DatabaseConfiguration.cs | 3 ++ .../RavenPersistenceConfiguration.cs | 17 ++++----- .../SharedEmbeddedServer.cs | 2 +- ...rovals.PlatformSampleSettings.approved.txt | 1 - .../Infrastructure/Settings/Settings.cs | 25 ------------- ...CheckMinimumStorageRequiredForIngestion.cs | 2 +- ...rovals.PlatformSampleSettings.approved.txt | 1 - .../Infrastructure/Settings/Settings.cs | 26 -------------- 10 files changed, 82 insertions(+), 66 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 0a34a77e47..956b7d6b89 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks { using System; + using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -13,7 +14,7 @@ class CheckFreeDiskSpace : CustomCheck public CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : base("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) { dataPath = databaseConfiguration.ServerConfiguration.DbPath; - percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; + percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); } @@ -42,9 +43,42 @@ public override Task PerformCheck(CancellationToken cancellationTok : CheckResult.Failed($"{percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'."); } + public static int Parse(IDictionary settings) + { + if (!settings.TryGetValue(RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey, out var thresholdValue)) + { + thresholdValue = $"{DataSpaceRemainingThresholdDefault}"; + } + + string message; + if (!int.TryParse(thresholdValue, out var threshold)) + { + message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} must be an integer."; + Logger.Fatal(message); + throw new Exception(message); + } + + if (threshold < 0) + { + message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, minimum value is 0."; + Logger.Fatal(message); + throw new Exception(message); + } + + if (threshold > 100) + { + message = $"{RavenPersistenceConfiguration.DataSpaceRemainingThresholdKey} is invalid, maximum value is 100."; + Logger.Fatal(message); + throw new Exception(message); + } + + return threshold; + } + readonly string dataPath; readonly decimal percentageThreshold; + public const int DataSpaceRemainingThresholdDefault = 20; static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 93c6cea29f..eb95428068 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -1,6 +1,7 @@ namespace ServiceControl.Audit.Persistence.RavenDB.CustomChecks { using System; + using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -49,6 +50,40 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Failed(message); } + public static int Parse(IDictionary settings) + { + if (!settings.TryGetValue(RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey, out var thresholdValue)) + { + thresholdValue = $"{MinimumStorageLeftRequiredForIngestionDefault}"; + } + + string message; + if (!int.TryParse(thresholdValue, out var threshold)) + { + message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; + Logger.Fatal(message); + throw new Exception(message); + } + + if (threshold < 0) + { + message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; + Logger.Fatal(message); + throw new Exception(message); + } + + if (threshold > 100) + { + message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; + Logger.Fatal(message); + throw new Exception(message); + } + + return threshold; + } + + public const int MinimumStorageLeftRequiredForIngestionDefault = 20; + static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs index 57db7a9af9..05f9258a31 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseConfiguration.cs @@ -9,6 +9,7 @@ public class DatabaseConfiguration( bool enableFullTextSearch, TimeSpan auditRetentionPeriod, int maxBodySizeToStore, + int dataSpaceRemainingThreshold, int minimumStorageLeftRequiredForIngestion, ServerConfiguration serverConfiguration, TimeSpan bulkInsertCommitTimeout) @@ -27,6 +28,8 @@ public class DatabaseConfiguration( public int MaxBodySizeToStore { get; } = maxBodySizeToStore; + public int DataSpaceRemainingThreshold { get; } = dataSpaceRemainingThreshold; + public int MinimumStorageLeftRequiredForIngestion { get; internal set; } = minimumStorageLeftRequiredForIngestion; //Setting for ATT only public TimeSpan BulkInsertCommitTimeout { get; } = bulkInsertCommitTimeout; diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index 6ff26714ff..12a1e7a5e7 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Reflection; + using CustomChecks; using NServiceBus.Logging; public class RavenPersistenceConfiguration : IPersistenceConfiguration @@ -17,6 +18,7 @@ public class RavenPersistenceConfiguration : IPersistenceConfiguration public const string RavenDbLogLevelKey = "RavenDBLogLevel"; public const string MinimumStorageLeftRequiredForIngestionKey = "MinimumStorageLeftRequiredForIngestion"; public const string BulkInsertCommitTimeoutInSecondsKey = "BulkInsertCommitTimeoutInSeconds"; + public const string DataSpaceRemainingThresholdKey = "DataSpaceRemainingThreshold"; public IEnumerable ConfigurationKeys => new[]{ DatabaseNameKey, @@ -26,6 +28,7 @@ public class RavenPersistenceConfiguration : IPersistenceConfiguration ExpirationProcessTimerInSecondsKey, LogPathKey, RavenDbLogLevelKey, + DataSpaceRemainingThresholdKey, MinimumStorageLeftRequiredForIngestionKey, BulkInsertCommitTimeoutInSecondsKey }; @@ -91,15 +94,8 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin serverConfiguration = new ServerConfiguration(dbPath, serverUrl, logPath, logsMode); } - if (!settings.PersisterSpecificSettings.TryGetValue(MinimumStorageLeftRequiredForIngestionKey, out var minimumStorageLeftRequiredForIngestionKey)) - { - minimumStorageLeftRequiredForIngestionKey = "5"; - } - - if (!int.TryParse(minimumStorageLeftRequiredForIngestionKey, out var minimumStorageLeftRequiredForIngestion)) - { - throw new InvalidOperationException($"{MinimumStorageLeftRequiredForIngestionKey} must be an integer."); - } + var dataSpaceRemainingThreshold = CheckFreeDiskSpace.Parse(settings.PersisterSpecificSettings); + var minimumStorageLeftRequiredForIngestion = CheckMinimumStorageRequiredForIngestion.Parse(settings.PersisterSpecificSettings); var expirationProcessTimerInSeconds = GetExpirationProcessTimerInSeconds(settings); @@ -111,6 +107,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin settings.EnableFullTextSearchOnBodies, settings.AuditRetentionPeriod, settings.MaxBodySizeToStore, + dataSpaceRemainingThreshold, minimumStorageLeftRequiredForIngestion, serverConfiguration, bulkInsertTimeout); @@ -182,4 +179,4 @@ static string GetLogPath(PersistenceSettings settings) const int ExpirationProcessTimerInSecondsDefault = 600; const int BulkInsertCommitTimeoutInSecondsDefault = 60; } -} \ No newline at end of file +} diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs index a67510e187..58f82595d8 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs @@ -35,7 +35,7 @@ public static async Task GetInstance(CancellationToken cancell var logsMode = "Operations"; var serverUrl = $"http://localhost:{PortUtility.FindAvailablePort(33334)}"; - embeddedDatabase = EmbeddedDatabase.Start(new DatabaseConfiguration("audit", 60, true, TimeSpan.FromMinutes(5), 120000, 5, new ServerConfiguration(dbPath, serverUrl, logPath, logsMode), TimeSpan.FromSeconds(60)), new ApplicationLifetime(new NullLogger())); + embeddedDatabase = EmbeddedDatabase.Start(new DatabaseConfiguration("audit", 60, true, TimeSpan.FromMinutes(5), 120000, 5, 5, new ServerConfiguration(dbPath, serverUrl, logPath, logsMode), TimeSpan.FromSeconds(60)), new ApplicationLifetime(new NullLogger())); //make sure that the database is up using var documentStore = await embeddedDatabase.Connect(cancellationToken); diff --git a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index eeed019adb..a382abd062 100644 --- a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -27,7 +27,6 @@ "ServiceName": "Particular.ServiceControl.Audit", "TransportConnectionString": null, "MaximumConcurrencyLevel": 32, - "DataSpaceRemainingThreshold": 20, "ServiceControlQueueAddress": "Particular.ServiceControl", "TimeToRestartAuditIngestionAfterFailure": "00:01:00", "EnableFullTextSearchOnBodies": true diff --git a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs index a308be179a..7d257da8e7 100644 --- a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs @@ -42,7 +42,6 @@ public Settings(string serviceName = null, string transportType = null, string p AuditRetentionPeriod = GetAuditRetentionPeriod(); Port = SettingsReader.Read(SettingsRootNamespace, "Port", 44444); MaximumConcurrencyLevel = SettingsReader.Read(SettingsRootNamespace, "MaximumConcurrencyLevel", 32); - DataSpaceRemainingThreshold = GetDataSpaceRemainingThreshold(); ServiceControlQueueAddress = SettingsReader.Read(SettingsRootNamespace, "ServiceControlQueueAddress"); TimeToRestartAuditIngestionAfterFailure = GetTimeToRestartAuditIngestionAfterFailure(); EnableFullTextSearchOnBodies = SettingsReader.Read(SettingsRootNamespace, "EnableFullTextSearchOnBodies", true); @@ -146,8 +145,6 @@ public int MaxBodySizeToStore public string TransportConnectionString { get; set; } public int MaximumConcurrencyLevel { get; set; } - public int DataSpaceRemainingThreshold { get; set; } - public string ServiceControlQueueAddress { get; set; } public TimeSpan TimeToRestartAuditIngestionAfterFailure { get; set; } @@ -279,27 +276,6 @@ static string Subscope(string address) return $"{queue}.log@{machine}"; } - int GetDataSpaceRemainingThreshold() - { - string message; - var threshold = SettingsReader.Read(SettingsRootNamespace, "DataSpaceRemainingThreshold", DataSpaceRemainingThresholdDefault); - if (threshold < 0) - { - message = $"{nameof(DataSpaceRemainingThreshold)} is invalid, minimum value is 0."; - logger.Fatal(message); - throw new Exception(message); - } - - if (threshold > 100) - { - message = $"{nameof(DataSpaceRemainingThreshold)} is invalid, maximum value is 100."; - logger.Fatal(message); - throw new Exception(message); - } - - return threshold; - } - void TryLoadLicenseFromConfig() => LicenseFileText = SettingsReader.Read(SettingsRootNamespace, "LicenseText"); // logger is intentionally not static to prevent it from being initialized before LoggingConfigurator.ConfigureLogging has been called @@ -311,6 +287,5 @@ int GetDataSpaceRemainingThreshold() public static readonly SettingsRootNamespace SettingsRootNamespace = new("ServiceControl.Audit"); const int MaxBodySizeToStoreDefault = 102400; //100 kb - const int DataSpaceRemainingThresholdDefault = 20; } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 8c75d426b0..44b2485755 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -69,7 +69,7 @@ public static void Validate(RavenPersisterSettings settings) } } - public const int MinimumStorageLeftRequiredForIngestionDefault = 5; + public const int MinimumStorageLeftRequiredForIngestionDefault = 20; readonly string dataPathRoot = Path.GetPathRoot(settings.DatabasePath); diff --git a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt index 9db0b6043b..17eb857f3c 100644 --- a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -43,6 +43,5 @@ "MaximumConcurrencyLevel": 10, "RetryHistoryDepth": 10, "RemoteInstances": [], - "DataSpaceRemainingThreshold": 20, "DisableHealthChecks": false } \ No newline at end of file diff --git a/src/ServiceControl/Infrastructure/Settings/Settings.cs b/src/ServiceControl/Infrastructure/Settings/Settings.cs index e35f191470..004688c0cf 100644 --- a/src/ServiceControl/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl/Infrastructure/Settings/Settings.cs @@ -59,7 +59,6 @@ public class Settings AllowMessageEditing = SettingsReader.Read(SettingsRootNamespace, "AllowMessageEditing"); NotificationsFilter = SettingsReader.Read(SettingsRootNamespace, "NotificationsFilter"); RemoteInstances = GetRemoteInstances().ToArray(); - DataSpaceRemainingThreshold = GetDataSpaceRemainingThreshold(); TimeToRestartErrorIngestionAfterFailure = GetTimeToRestartErrorIngestionAfterFailure(); DisableExternalIntegrationsPublishing = SettingsReader.Read(SettingsRootNamespace, "DisableExternalIntegrationsPublishing", false); @@ -178,8 +177,6 @@ public TimeSpan HeartbeatGracePeriod public RemoteInstanceSetting[] RemoteInstances { get; set; } - public int DataSpaceRemainingThreshold { get; set; } - public bool DisableHealthChecks { get; set; } public ITransportCustomization LoadTransportCustomization() @@ -386,27 +383,6 @@ static string Subscope(string address) return $"{queue}.log@{machine}"; } - int GetDataSpaceRemainingThreshold() - { - string message; - var threshold = SettingsReader.Read(SettingsRootNamespace, "DataSpaceRemainingThreshold", DataSpaceRemainingThresholdDefault); - if (threshold < 0) - { - message = $"{nameof(DataSpaceRemainingThreshold)} is invalid, minimum value is 0."; - logger.Fatal(message); - throw new Exception(message); - } - - if (threshold > 100) - { - message = $"{nameof(DataSpaceRemainingThreshold)} is invalid, maximum value is 100."; - logger.Fatal(message); - throw new Exception(message); - } - - return threshold; - } - void LoadErrorIngestionSettings() { var serviceBusRootNamespace = new SettingsRootNamespace("ServiceBus"); @@ -440,7 +416,5 @@ void LoadErrorIngestionSettings() public const string DEFAULT_SERVICE_NAME = "Particular.ServiceControl"; public static readonly SettingsRootNamespace SettingsRootNamespace = new("ServiceControl"); - - const int DataSpaceRemainingThresholdDefault = 20; } } \ No newline at end of file From 46187da0b60b4c889b673ba84973a14280ecf179 Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Thu, 28 Mar 2024 15:28:23 +0100 Subject: [PATCH 04/14] Keep sane thresholds --- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 2 +- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 2 +- src/ServiceControl/App.config | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index eb95428068..ffa8a80915 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -82,7 +82,7 @@ public static int Parse(IDictionary settings) return threshold; } - public const int MinimumStorageLeftRequiredForIngestionDefault = 20; + public const int MinimumStorageLeftRequiredForIngestionDefault = 5; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 44b2485755..8c75d426b0 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -69,7 +69,7 @@ public static void Validate(RavenPersisterSettings settings) } } - public const int MinimumStorageLeftRequiredForIngestionDefault = 20; + public const int MinimumStorageLeftRequiredForIngestionDefault = 5; readonly string dataPathRoot = Path.GetPathRoot(settings.DatabasePath); diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index 27afc99c1d..2ffc12fdd6 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -22,7 +22,7 @@ These settings are only here so that we can debug ServiceControl while developin - + From 5b5416b81166b45091e0bf724d1285fda56d5e4d Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Thu, 28 Mar 2024 18:02:06 +0100 Subject: [PATCH 05/14] Fix custom check tests by resolving them from the container and introduce the same test in the main instance --- ...CustomChecksServiceCollectionExtensions.cs | 15 ++++++++ .../RavenPersistence.cs | 6 +++- ...CheckTests.VerifyCustomChecks.approved.txt | 3 +- .../PersistenceTestsConfiguration.cs | 14 ++++---- .../CustomCheckTests.cs | 23 ++----------- .../InMemory/PersistenceTestsConfiguration.cs | 34 ++++++++----------- .../PersistenceTestFixture.cs | 2 ++ ...CheckTests.VerifyCustomChecks.approved.txt | 5 +++ .../CustomCheckTests.cs | 24 +++++++++++++ .../PersistenceTestBase.cs | 1 + 10 files changed, 77 insertions(+), 50 deletions(-) create mode 100644 src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs create mode 100644 src/ServiceControl.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt create mode 100644 src/ServiceControl.Persistence.Tests/CustomCheckTests.cs diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs b/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs new file mode 100644 index 0000000000..6a52393001 --- /dev/null +++ b/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs @@ -0,0 +1,15 @@ +namespace ServiceControl.Audit.Persistence.RavenDB +{ + using Microsoft.Extensions.DependencyInjection; + using NServiceBus.CustomChecks; + + static class InternalCustomChecksServiceCollectionExtensions + { + public static void AddCustomCheck(this IServiceCollection serviceCollection) + where T : class, ICustomCheck + { + serviceCollection.AddTransient(); // Allows for T to have different instance registered for testing + serviceCollection.AddTransient(b => b.GetService()); + } + } +} \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs index 2c92f4f07e..537a358aa7 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs @@ -1,8 +1,8 @@ namespace ServiceControl.Audit.Persistence.RavenDB { + using CustomChecks; using Microsoft.Extensions.DependencyInjection; using Persistence.UnitOfWork; - using RavenDB.CustomChecks; using UnitOfWork; class RavenPersistence(DatabaseConfiguration databaseConfiguration) : IPersistence @@ -15,6 +15,10 @@ public void AddPersistence(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + + services.AddCustomCheck(); + services.AddCustomCheck(); + services.AddCustomCheck(); } public void AddInstaller(IServiceCollection services) => ConfigureLifecycle(services, databaseConfiguration); diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt index 1395d49c0b..2dd77f440a 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt @@ -1,2 +1,3 @@ ServiceControl.Audit Health: Audit Database Index Lag -ServiceControl.Audit Health: Audit Message Ingestion Process \ No newline at end of file +ServiceControl.Audit Health: Audit Message Ingestion Process +Storage space: ServiceControl.Audit database \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs index 77c312a2ec..1c8992367e 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs @@ -15,10 +15,13 @@ class PersistenceTestsConfiguration { - public IAuditDataStore AuditDataStore { get; protected set; } - public IFailedAuditStorage FailedAuditStorage { get; protected set; } - public IBodyStorage BodyStorage { get; set; } - public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; protected set; } + public IAuditDataStore AuditDataStore { get; private set; } + public IFailedAuditStorage FailedAuditStorage { get; private set; } + public IBodyStorage BodyStorage { get; private set; } + public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; private set; } + public IDocumentStore DocumentStore { get; private set; } + public IServiceProvider ServiceProvider => host.Services; + public string Name => "RavenDB"; public async Task Configure(Action setSettings) { @@ -92,9 +95,6 @@ public async Task Cleanup() host.Dispose(); } - public string Name => "RavenDB"; - - public IDocumentStore DocumentStore { get; private set; } string databaseName; IHost host; diff --git a/src/ServiceControl.Audit.Persistence.Tests/CustomCheckTests.cs b/src/ServiceControl.Audit.Persistence.Tests/CustomCheckTests.cs index 12cfefbb26..c50e624880 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/CustomCheckTests.cs +++ b/src/ServiceControl.Audit.Persistence.Tests/CustomCheckTests.cs @@ -1,8 +1,8 @@ namespace ServiceControl.Audit.Persistence.Tests { using System; - using System.Collections.Generic; using System.Linq; + using Microsoft.Extensions.DependencyInjection; using NServiceBus.CustomChecks; using NUnit.Framework; using Particular.Approvals; @@ -15,29 +15,10 @@ class CustomCheckTests : PersistenceTestFixture // If any changes have been made to custom checks, this may break customer integration subscribers. Approver.Verify( string.Join(Environment.NewLine, - from check in GetCustomChecks() + from check in ServiceProvider.GetServices() orderby check.Category, check.Id select $"{check.Category}: {check.Id}" ) ); - - IEnumerable GetCustomChecks() - { - var customCheckTypes = DataStore.GetType().Assembly - .GetTypes() - .Where(t => t.IsAbstract == false && typeof(ICustomCheck).IsAssignableFrom(t)); - - var settings = new object(); - - foreach (var customCheckType in customCheckTypes) - { - var constructor = customCheckType.GetConstructors().Single(); - var constructorParameters = constructor.GetParameters() - .Select(p => p.ParameterType.Name == "Settings" ? settings : null) - .ToArray(); - var instance = (ICustomCheck)constructor.Invoke(constructorParameters); - yield return instance; - } - } } } diff --git a/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs b/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs index 9d1ffed132..db46fbf2c0 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs @@ -7,12 +7,14 @@ using ServiceControl.Audit.Persistence.InMemory; using UnitOfWork; - partial class PersistenceTestsConfiguration + class PersistenceTestsConfiguration { - public IAuditDataStore AuditDataStore { get; protected set; } - public IFailedAuditStorage FailedAuditStorage { get; protected set; } - public IBodyStorage BodyStorage { get; protected set; } - public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; protected set; } + public IAuditDataStore AuditDataStore { get; private set; } + public IFailedAuditStorage FailedAuditStorage { get; private set; } + public IBodyStorage BodyStorage { get; private set; } + public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; private set; } + public IServiceProvider ServiceProvider { get; private set; } + public string Name => "InMemory"; public Task Configure(Action setSettings) { @@ -24,24 +26,16 @@ public Task Configure(Action setSettings) var persistence = config.Create(settings); persistence.AddPersistence(serviceCollection); - var serviceProvider = serviceCollection.BuildServiceProvider(); - AuditDataStore = serviceProvider.GetRequiredService(); - FailedAuditStorage = serviceProvider.GetRequiredService(); - BodyStorage = serviceProvider.GetService(); - AuditIngestionUnitOfWorkFactory = serviceProvider.GetRequiredService(); + ServiceProvider = serviceCollection.BuildServiceProvider(); + AuditDataStore = ServiceProvider.GetRequiredService(); + FailedAuditStorage = ServiceProvider.GetRequiredService(); + BodyStorage = ServiceProvider.GetService(); + AuditIngestionUnitOfWorkFactory = ServiceProvider.GetRequiredService(); return Task.CompletedTask; } - public Task CompleteDBOperation() - { - return Task.CompletedTask; - } + public Task CompleteDBOperation() => Task.CompletedTask; - public Task Cleanup() - { - return Task.CompletedTask; - } - - public string Name => "InMemory"; + public Task Cleanup() => Task.CompletedTask; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.Tests/PersistenceTestFixture.cs b/src/ServiceControl.Audit.Persistence.Tests/PersistenceTestFixture.cs index cf358d9a31..207c098bc6 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/PersistenceTestFixture.cs +++ b/src/ServiceControl.Audit.Persistence.Tests/PersistenceTestFixture.cs @@ -61,6 +61,8 @@ protected string GetManifestPath() protected IAuditIngestionUnitOfWork StartAuditUnitOfWork(int batchSize) => AuditIngestionUnitOfWorkFactory.StartNew(batchSize); + protected IServiceProvider ServiceProvider => configuration.ServiceProvider; + protected PersistenceTestsConfiguration configuration; } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt b/src/ServiceControl.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt new file mode 100644 index 0000000000..1230037975 --- /dev/null +++ b/src/ServiceControl.Persistence.Tests.RavenDB/ApprovalFiles/CustomCheckTests.VerifyCustomChecks.approved.txt @@ -0,0 +1,5 @@ +Health: Saga Audit Destination +ServiceControl Health: Error Database Index Errors +ServiceControl Health: Error Database Index Lag +ServiceControl Health: Message Ingestion Process +Storage space: ServiceControl database \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests/CustomCheckTests.cs b/src/ServiceControl.Persistence.Tests/CustomCheckTests.cs new file mode 100644 index 0000000000..744f57e34b --- /dev/null +++ b/src/ServiceControl.Persistence.Tests/CustomCheckTests.cs @@ -0,0 +1,24 @@ +namespace ServiceControl.PersistenceTests +{ + using System; + using System.Linq; + using Microsoft.Extensions.DependencyInjection; + using NServiceBus.CustomChecks; + using NUnit.Framework; + using Particular.Approvals; + + class CustomCheckTests : PersistenceTestBase + { + [Test] + public void VerifyCustomChecks() => + // HINT: Custom checks are documented on the docs site and Id and Category are published in integration events + // If any changes have been made to custom checks, this may break customer integration subscribers. + Approver.Verify( + string.Join(Environment.NewLine, + from check in ServiceProvider.GetServices() + orderby check.Category, check.Id + select $"{check.Category}: {check.Id}" + ) + ); + } +} diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index 7a974dda74..a20619bdb4 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -90,6 +90,7 @@ protected PersistenceSettings PersistenceSettings protected IDocumentStore DocumentStore { get; private set; } protected IRavenSessionProvider SessionProvider { get; private set; } + protected IServiceProvider ServiceProvider => host.Services; protected T GetRequiredService() => host.Services.GetRequiredService(); protected object GetRequiredService(Type serviceType) => host.Services.GetRequiredService(serviceType); From 99be266b1e8e4bbec80891f3276c3c8d150a7f39 Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Thu, 28 Mar 2024 18:03:08 +0100 Subject: [PATCH 06/14] Change to direct service provider usage instead --- .../Archiving/ArchiveGroupTests.cs | 4 +-- .../RavenAttachmentsBodyStorageTests.cs | 3 +- .../FailedErrorImportCustomCheckTests.cs | 4 +-- .../ErrorMessageDataStoreTests.cs | 3 +- .../Unarchiving/UnarchiveGroupTests.cs | 4 +-- .../EnsureSettingsInContainer.cs | 5 +-- .../PersistenceTestBase.cs | 32 ++++++++----------- .../Recoverability/EditMessageTests.cs | 2 +- 8 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs index 4b4c1235ee..a8699d079c 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs @@ -48,7 +48,7 @@ public async Task ArchiveGroup_skips_over_empty_batches_but_still_completes() await session.SaveChangesAsync(); } - var handler = GetRequiredService(); // See this.CreateHostBuilder + var handler = ServiceProvider.GetRequiredService(); // See this.CreateHostBuilder var context = new TestableMessageHandlerContext(); var message = new ArchiveAllInGroup { GroupId = groupId }; @@ -96,7 +96,7 @@ public async Task ArchiveGroup_GetGroupDetails_doesnt_fail_with_invalid_groupId( await session.SaveChangesAsync(); } - var handler = GetRequiredService(); // See this.CreateHostBuilder + var handler = ServiceProvider.GetRequiredService(); // See this.CreateHostBuilder var context = new TestableMessageHandlerContext(); var message = new ArchiveAllInGroup { GroupId = groupId + "Invalid" }; diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/BodyStorage/RavenAttachmentsBodyStorageTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/BodyStorage/RavenAttachmentsBodyStorageTests.cs index cd217f67f7..890a0648dc 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/BodyStorage/RavenAttachmentsBodyStorageTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/BodyStorage/RavenAttachmentsBodyStorageTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; using NServiceBus; using NServiceBus.Transport; using NUnit.Framework; @@ -33,7 +34,7 @@ async Task RunTest(Func, string> getIdToQuery) var contentType = "NotImportant"; var endpointName = "EndpointName"; var body = BitConverter.GetBytes(0xDEADBEEF); - var ingestionFactory = GetRequiredService(); + var ingestionFactory = ServiceProvider.GetRequiredService(); var headers = new Dictionary { diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/Operations/FailedErrorImportCustomCheckTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/Operations/FailedErrorImportCustomCheckTests.cs index 7d7bbeefbc..908eacc48f 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/Operations/FailedErrorImportCustomCheckTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/Operations/FailedErrorImportCustomCheckTests.cs @@ -21,7 +21,7 @@ public async Task Pass_if_no_failed_imports() { await DocumentStore.ExecuteIndexAsync(new FailedErrorImportIndex()); - var customCheck = GetRequiredService(); + var customCheck = ServiceProvider.GetRequiredService(); var result = await customCheck.PerformCheck(); @@ -46,7 +46,7 @@ public async Task Fail_if_failed_imports() DocumentStore.WaitForIndexing(); - var customCheck = GetRequiredService(); + var customCheck = ServiceProvider.GetRequiredService(); var result = await customCheck.PerformCheck(); diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/Recoverability/ErrorMessageDataStoreTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/Recoverability/ErrorMessageDataStoreTests.cs index cd287527f4..03ef727bb0 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/Recoverability/ErrorMessageDataStoreTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/Recoverability/ErrorMessageDataStoreTests.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using ServiceControl.MessageFailures; using ServiceControl.Operations; @@ -60,7 +61,7 @@ public async Task GetStore() CompleteDatabaseOperation(); - store = GetRequiredService(); + store = ServiceProvider.GetRequiredService(); } async Task GenerateAndSaveFailedMessage() diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/Unarchiving/UnarchiveGroupTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/Unarchiving/UnarchiveGroupTests.cs index 2058945f13..7b0b24b7bc 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/Unarchiving/UnarchiveGroupTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/Unarchiving/UnarchiveGroupTests.cs @@ -46,7 +46,7 @@ public async Task UnarchiveGroup_skips_over_empty_batches_but_still_completes() await session.SaveChangesAsync(); } - var handler = GetRequiredService(); // See this.CreateHostBuilder + var handler = ServiceProvider.GetRequiredService(); // See this.CreateHostBuilder var context = new TestableMessageHandlerContext(); var message = new UnarchiveAllInGroup { GroupId = groupId }; @@ -94,7 +94,7 @@ public async Task UnarchiveGroup_GetGroupDetails_doesnt_fail_with_invalid_groupI await session.SaveChangesAsync(); } - var handler = GetRequiredService(); // See this.CreateHostBuilder + var handler = ServiceProvider.GetRequiredService(); // See this.CreateHostBuilder var context = new TestableMessageHandlerContext(); var message = new UnarchiveAllInGroup { GroupId = groupId + "Invalid" }; diff --git a/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs b/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs index 9773b566ea..cabc552742 100644 --- a/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs +++ b/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs @@ -1,5 +1,6 @@ namespace ServiceControl.PersistenceTests { + using Microsoft.Extensions.DependencyInjection; using NUnit.Framework; using ServiceControl.Persistence; @@ -9,13 +10,13 @@ public sealed class EnsureSettingsInContainer : PersistenceTestBase public void CheckForBothTypes() { // Persistence implementation must register singleton as base type as some compoennts need to inject that - var baseSettings = GetRequiredService(); + var baseSettings = ServiceProvider.GetRequiredService(); var actualType = baseSettings.GetType(); Assert.AreNotEqual(actualType, typeof(PersistenceSettings)); // Persistence implementation must also register the same singleton as the persister-specific type - var settingsAsActualType = GetRequiredService(actualType); + var settingsAsActualType = ServiceProvider.GetRequiredService(actualType); Assert.AreSame(baseSettings, settingsAsActualType); } } diff --git a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs index a20619bdb4..1daab33c52 100644 --- a/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs +++ b/src/ServiceControl.Persistence.Tests/PersistenceTestBase.cs @@ -1,10 +1,8 @@ using System; using System.Diagnostics; -using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using NServiceBus; using NServiceBus.Settings; @@ -91,10 +89,6 @@ protected PersistenceSettings PersistenceSettings protected IDocumentStore DocumentStore { get; private set; } protected IRavenSessionProvider SessionProvider { get; private set; } protected IServiceProvider ServiceProvider => host.Services; - - protected T GetRequiredService() => host.Services.GetRequiredService(); - protected object GetRequiredService(Type serviceType) => host.Services.GetRequiredService(serviceType); - protected Action RegisterServices { get; set; } = _ => { }; protected void CompleteDatabaseOperation() => DocumentStore.WaitForIndexing(); @@ -145,17 +139,17 @@ protected void BlockToInspectDatabase() Debugger.Break(); } - protected IErrorMessageDataStore ErrorStore => GetRequiredService(); - protected IRetryDocumentDataStore RetryStore => GetRequiredService(); - protected IBodyStorage BodyStorage => GetRequiredService(); - protected IRetryBatchesDataStore RetryBatchesStore => GetRequiredService(); - protected IErrorMessageDataStore ErrorMessageDataStore => GetRequiredService(); - protected IMessageRedirectsDataStore MessageRedirectsDataStore => GetRequiredService(); - protected IMonitoringDataStore MonitoringDataStore => GetRequiredService(); - protected IIngestionUnitOfWorkFactory UnitOfWorkFactory => GetRequiredService(); - protected ICustomChecksDataStore CustomChecks => GetRequiredService(); - protected IArchiveMessages ArchiveMessages => GetRequiredService(); - protected IIngestionUnitOfWorkFactory IngestionUnitOfWorkFactory => GetRequiredService(); - protected IEventLogDataStore EventLogDataStore => GetRequiredService(); - protected IRetryDocumentDataStore RetryDocumentDataStore => GetRequiredService(); + protected IErrorMessageDataStore ErrorStore => ServiceProvider.GetRequiredService(); + protected IRetryDocumentDataStore RetryStore => ServiceProvider.GetRequiredService(); + protected IBodyStorage BodyStorage => ServiceProvider.GetRequiredService(); + protected IRetryBatchesDataStore RetryBatchesStore => ServiceProvider.GetRequiredService(); + protected IErrorMessageDataStore ErrorMessageDataStore => ServiceProvider.GetRequiredService(); + protected IMessageRedirectsDataStore MessageRedirectsDataStore => ServiceProvider.GetRequiredService(); + protected IMonitoringDataStore MonitoringDataStore => ServiceProvider.GetRequiredService(); + protected IIngestionUnitOfWorkFactory UnitOfWorkFactory => ServiceProvider.GetRequiredService(); + protected ICustomChecksDataStore CustomChecks => ServiceProvider.GetRequiredService(); + protected IArchiveMessages ArchiveMessages => ServiceProvider.GetRequiredService(); + protected IIngestionUnitOfWorkFactory IngestionUnitOfWorkFactory => ServiceProvider.GetRequiredService(); + protected IEventLogDataStore EventLogDataStore => ServiceProvider.GetRequiredService(); + protected IRetryDocumentDataStore RetryDocumentDataStore => ServiceProvider.GetRequiredService(); } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs b/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs index ae72e68669..f0fe64b6f8 100644 --- a/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs +++ b/src/ServiceControl.Persistence.Tests/Recoverability/EditMessageTests.cs @@ -27,7 +27,7 @@ sealed class EditMessageTests : PersistenceTestBase .AddTransient(); [SetUp] - public void Setup() => handler = GetRequiredService(); + public void Setup() => handler = ServiceProvider.GetRequiredService(); [Test] public async Task Should_discard_edit_when_failed_message_not_exists() From d438f1521f29d506bc6ccd2583dfa40fe1ae5152 Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Thu, 28 Mar 2024 17:43:10 +0100 Subject: [PATCH 07/14] Aligh custom checks and make sure they pass for external ravendb --- .../CustomChecks/CheckFreeDiskSpace.cs | 26 +++++++------- ...CheckMinimumStorageRequiredForIngestion.cs | 34 ++++++++++++------- .../CustomChecks/CheckFreeDiskSpace.cs | 30 ++++++++-------- ...CheckMinimumStorageRequiredForIngestion.cs | 34 ++++++++++++------- .../CustomChecks/CheckRavenDBIndexErrors.cs | 5 ++- .../CustomChecks/CheckRavenDBIndexLag.cs | 5 ++- .../RavenPersistence.cs | 1 + .../RavenPersistenceConfiguration.cs | 1 + .../RavenPersisterSettings.cs | 1 + 9 files changed, 80 insertions(+), 57 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 956b7d6b89..7b75c17ecd 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -9,22 +9,24 @@ using NServiceBus.Logging; using RavenDB; - class CheckFreeDiskSpace : CustomCheck + class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : CustomCheck("ServiceControl.Audit database", + "Storage space", TimeSpan.FromMinutes(5)) { - public CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : base("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) - { - dataPath = databaseConfiguration.ServerConfiguration.DbPath; - percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { - var dataPathRoot = Path.GetPathRoot(dataPath); + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); + } + + if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) + { + return CheckResult.Pass; + } if (dataPathRoot == null) { - throw new Exception($"Unable to find the root of the data path {dataPath}"); + throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); @@ -75,8 +77,8 @@ public static int Parse(IDictionary settings) return threshold; } - readonly string dataPath; - readonly decimal percentageThreshold; + readonly string dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); + readonly decimal percentageThreshold = databaseConfiguration.DataSpaceRemainingThreshold / 100m; public const int DataSpaceRemainingThresholdDefault = 20; static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index ffa8a80915..43e624ab31 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -9,23 +9,29 @@ using NServiceBus.Logging; using RavenDB; - class CheckMinimumStorageRequiredForIngestion( - MinimumRequiredStorageState stateHolder, - DatabaseConfiguration databaseConfiguration) - : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion : CustomCheck { - public override Task PerformCheck(CancellationToken cancellationToken = default) + public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, + DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { - var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; + this.stateHolder = stateHolder; + this.databaseConfiguration = databaseConfiguration; + percentageThreshold = this.databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; + dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); + } - var dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); - if (dataPathRoot == null) + public override Task PerformCheck(CancellationToken cancellationToken = default) + { + if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) { stateHolder.CanIngestMore = true; - return SuccessResult; + return CheckResult.Pass; } - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + } var dataDriveInfo = new DriveInfo(dataPathRoot); var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; @@ -41,7 +47,7 @@ public override Task PerformCheck(CancellationToken cancellationTok if (percentRemaining > percentageThreshold) { stateHolder.CanIngestMore = true; - return SuccessResult; + return CheckResult.Pass; } var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; @@ -84,7 +90,11 @@ public static int Parse(IDictionary settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); + readonly string dataPathRoot; + readonly decimal percentageThreshold; + readonly MinimumRequiredStorageState stateHolder; + readonly DatabaseConfiguration databaseConfiguration; + static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 649f4017c4..fa29df91af 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -1,4 +1,4 @@ -namespace ServiceControl.Operations +namespace ServiceControl.Persistence.RavenDB.CustomChecks { using System; using System.IO; @@ -6,24 +6,26 @@ using System.Threading.Tasks; using NServiceBus.CustomChecks; using NServiceBus.Logging; - using Persistence.RavenDB; + using ServiceControl.Persistence.RavenDB; - class CheckFreeDiskSpace : CustomCheck + class CheckFreeDiskSpace(RavenPersisterSettings settings) + : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) { - public CheckFreeDiskSpace(RavenPersisterSettings settings) : base("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) - { - dataPath = settings.DatabasePath; - percentageThreshold = settings.DataSpaceRemainingThreshold / 100m; - Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { - var dataPathRoot = Path.GetPathRoot(dataPath); + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space remaining custom check starting. Threshold {percentageThreshold:P0}"); + } + + if (!settings.UseEmbeddedServer) + { + return CheckResult.Pass; + } if (dataPathRoot == null) { - throw new Exception($"Unable to find the root of the data path {dataPath}"); + throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); @@ -63,8 +65,8 @@ public static void Validate(RavenPersisterSettings settings) } } - readonly string dataPath; - readonly decimal percentageThreshold; + readonly string dataPathRoot = Path.GetPathRoot(settings.DatabasePath); + readonly decimal percentageThreshold = settings.DataSpaceRemainingThreshold / 100m; public const int DataSpaceRemainingThresholdDefault = 20; static readonly ILog Logger = LogManager.GetLogger(typeof(CheckFreeDiskSpace)); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 8c75d426b0..5223a18910 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -1,4 +1,4 @@ -namespace ServiceControl.Operations +namespace ServiceControl.Persistence.RavenDB.CustomChecks { using System; using System.IO; @@ -6,25 +6,32 @@ using System.Threading.Tasks; using NServiceBus.CustomChecks; using NServiceBus.Logging; - using Persistence.RavenDB; using ServiceControl.Persistence; + using ServiceControl.Persistence.RavenDB; - class CheckMinimumStorageRequiredForIngestion( - MinimumRequiredStorageState stateHolder, - RavenPersisterSettings settings) - : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) + class CheckMinimumStorageRequiredForIngestion : CustomCheck { - public override Task PerformCheck(CancellationToken cancellationToken = default) + public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, + RavenPersisterSettings settings) : base("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { - percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; + this.stateHolder = stateHolder; + this.settings = settings; + dataPathRoot = Path.GetPathRoot(settings.DatabasePath); + percentageThreshold = this.settings.MinimumStorageLeftRequiredForIngestion / 100m; + } - if (dataPathRoot == null) + public override Task PerformCheck(CancellationToken cancellationToken = default) + { + if (!settings.UseEmbeddedServer) { stateHolder.CanIngestMore = true; return SuccessResult; } - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + } var dataDriveInfo = new DriveInfo(dataPathRoot); var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; @@ -71,9 +78,10 @@ public static void Validate(RavenPersisterSettings settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - readonly string dataPathRoot = Path.GetPathRoot(settings.DatabasePath); - - decimal percentageThreshold; + readonly string dataPathRoot; + readonly decimal percentageThreshold; + readonly MinimumRequiredStorageState stateHolder; + readonly RavenPersisterSettings settings; static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs index 2cdd727469..41e3e97c0a 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs @@ -1,4 +1,4 @@ -namespace ServiceControl +namespace ServiceControl.Persistence.RavenDB.CustomChecks { using System; using System.Linq; @@ -7,9 +7,8 @@ using System.Threading.Tasks; using NServiceBus.CustomChecks; using NServiceBus.Logging; - using Persistence.RavenDB; - using Raven.Client.Documents; using Raven.Client.Documents.Operations.Indexes; + using ServiceControl.Persistence.RavenDB; class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 655214e150..662ddcdadb 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -1,4 +1,4 @@ -namespace ServiceControl +namespace ServiceControl.Persistence.RavenDB.CustomChecks { using System; using System.Linq; @@ -7,9 +7,8 @@ using System.Threading.Tasks; using NServiceBus.CustomChecks; using NServiceBus.Logging; - using Persistence.RavenDB; - using Raven.Client.Documents; using Raven.Client.Documents.Operations; + using ServiceControl.Persistence.RavenDB; using CustomCheck = NServiceBus.CustomChecks.CustomCheck; class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Lag", "ServiceControl Health", TimeSpan.FromMinutes(5)) diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs index 6e5a4323ef..5a4cadc2de 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs @@ -1,5 +1,6 @@ namespace ServiceControl.Persistence.RavenDB { + using CustomChecks; using MessageRedirects; using Microsoft.Extensions.DependencyInjection; using NServiceBus.Unicast.Subscriptions.MessageDrivenSubscriptions; diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs index dc33a09549..adc088b761 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -4,6 +4,7 @@ using System.IO; using System.Reflection; using Configuration; + using CustomChecks; using ServiceControl.Operations; class RavenPersistenceConfiguration : IPersistenceConfiguration diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs index 1ebaf4adeb..307d850ede 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs @@ -1,6 +1,7 @@ using System; using ServiceControl.Operations; using ServiceControl.Persistence; +using ServiceControl.Persistence.RavenDB.CustomChecks; class RavenPersisterSettings : PersistenceSettings { From 5c755c7ff636b49cca2c4b5fcdb0e59d485bdc09 Mon Sep 17 00:00:00 2001 From: danielmarbach Date: Thu, 28 Mar 2024 17:46:09 +0100 Subject: [PATCH 08/14] Further small alignment --- ...CheckMinimumStorageRequiredForIngestion.cs | 30 +++++++++++++------ ...CheckMinimumStorageRequiredForIngestion.cs | 9 ++++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 43e624ab31..2ca7d06644 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -12,7 +12,8 @@ class CheckMinimumStorageRequiredForIngestion : CustomCheck { public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, - DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) + DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", + "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { this.stateHolder = stateHolder; this.databaseConfiguration = databaseConfiguration; @@ -22,15 +23,20 @@ class CheckMinimumStorageRequiredForIngestion : CustomCheck public override Task PerformCheck(CancellationToken cancellationToken = default) { + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + } + if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) { stateHolder.CanIngestMore = true; return CheckResult.Pass; } - if (Logger.IsDebugEnabled) + if (dataPathRoot == null) { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); @@ -41,7 +47,8 @@ public override Task PerformCheck(CancellationToken cancellationTok if (Logger.IsDebugEnabled) { - Logger.Debug($"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); + Logger.Debug( + $"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); } if (percentRemaining > percentageThreshold) @@ -50,7 +57,8 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; + var message = + $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; Logger.Warn(message); stateHolder.CanIngestMore = false; return CheckResult.Failed(message); @@ -58,7 +66,8 @@ public override Task PerformCheck(CancellationToken cancellationTok public static int Parse(IDictionary settings) { - if (!settings.TryGetValue(RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey, out var thresholdValue)) + if (!settings.TryGetValue(RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey, + out var thresholdValue)) { thresholdValue = $"{MinimumStorageLeftRequiredForIngestionDefault}"; } @@ -66,21 +75,24 @@ public static int Parse(IDictionary settings) string message; if (!int.TryParse(thresholdValue, out var threshold)) { - message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; + message = + $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; Logger.Fatal(message); throw new Exception(message); } if (threshold < 0) { - message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; + message = + $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; Logger.Fatal(message); throw new Exception(message); } if (threshold > 100) { - message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; + message = + $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; Logger.Fatal(message); throw new Exception(message); } diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 5223a18910..4feac0d238 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -22,15 +22,20 @@ class CheckMinimumStorageRequiredForIngestion : CustomCheck public override Task PerformCheck(CancellationToken cancellationToken = default) { + if (Logger.IsDebugEnabled) + { + Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + } + if (!settings.UseEmbeddedServer) { stateHolder.CanIngestMore = true; return SuccessResult; } - if (Logger.IsDebugEnabled) + if (dataPathRoot == null) { - Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); + throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); From 84acff929d8847b7d26d504a9244865f4e4299da Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Wed, 3 Apr 2024 16:16:29 -0400 Subject: [PATCH 09/14] Formatting --- .../CustomChecks/CheckFreeDiskSpace.cs | 3 +-- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 4 +--- .../CustomChecks/CheckRavenDBIndexLag.cs | 3 +-- .../CustomChecks/CheckFreeDiskSpace.cs | 3 +-- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 3 +-- .../CustomChecks/CheckRavenDBIndexErrors.cs | 3 +-- src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs | 1 - .../RavenPersistenceConfiguration.cs | 1 - .../RavenPersisterSettings.cs | 1 - .../Archiving/ArchiveGroupTests.cs | 2 -- .../EnsureSettingsInContainer.cs | 2 +- 11 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 7b75c17ecd..a1a98b86d9 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -9,8 +9,7 @@ using NServiceBus.Logging; using RavenDB; - class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : CustomCheck("ServiceControl.Audit database", - "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(DatabaseConfiguration databaseConfiguration) : CustomCheck("ServiceControl.Audit database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 2ca7d06644..4204b6d29e 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -11,9 +11,7 @@ class CheckMinimumStorageRequiredForIngestion : CustomCheck { - public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, - DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", - "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) + public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { this.stateHolder = stateHolder; this.databaseConfiguration = databaseConfiguration; diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs index 94eb561d06..ba9af287e7 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexLag.cs @@ -10,8 +10,7 @@ using Raven.Client.Documents.Operations; using ServiceControl.Audit.Persistence.RavenDB; - class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) - : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexLag(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Audit Database Index Lag", "ServiceControl.Audit Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index fa29df91af..0047a7ac35 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -8,8 +8,7 @@ using NServiceBus.Logging; using ServiceControl.Persistence.RavenDB; - class CheckFreeDiskSpace(RavenPersisterSettings settings) - : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) + class CheckFreeDiskSpace(RavenPersisterSettings settings) : CustomCheck("ServiceControl database", "Storage space", TimeSpan.FromMinutes(5)) { public override Task PerformCheck(CancellationToken cancellationToken = default) { diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 4feac0d238..edde4d3ea8 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -11,8 +11,7 @@ class CheckMinimumStorageRequiredForIngestion : CustomCheck { - public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, - RavenPersisterSettings settings) : base("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) + public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings) : base("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { this.stateHolder = stateHolder; this.settings = settings; diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs index 41e3e97c0a..cb3f817ba2 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckRavenDBIndexErrors.cs @@ -10,8 +10,7 @@ using Raven.Client.Documents.Operations.Indexes; using ServiceControl.Persistence.RavenDB; - class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Errors", - "ServiceControl Health", TimeSpan.FromMinutes(5)) + class CheckRavenDBIndexErrors(IRavenDocumentStoreProvider documentStoreProvider) : CustomCheck("Error Database Index Errors", "ServiceControl Health", TimeSpan.FromMinutes(5)) { public override async Task PerformCheck(CancellationToken cancellationToken = default) { diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs index 5a4cadc2de..aef02607b8 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistence.cs @@ -9,7 +9,6 @@ using ServiceControl.CustomChecks; using ServiceControl.Infrastructure.RavenDB.Subscriptions; using ServiceControl.MessageFailures; - using ServiceControl.Operations; using ServiceControl.Operations.BodyStorage; using ServiceControl.Operations.BodyStorage.RavenAttachments; using ServiceControl.Persistence.MessageRedirects; diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs index adc088b761..a13ecd1a31 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersistenceConfiguration.cs @@ -5,7 +5,6 @@ using System.Reflection; using Configuration; using CustomChecks; - using ServiceControl.Operations; class RavenPersistenceConfiguration : IPersistenceConfiguration { diff --git a/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs b/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs index 307d850ede..12bc02323d 100644 --- a/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs +++ b/src/ServiceControl.Persistence.RavenDB/RavenPersisterSettings.cs @@ -1,5 +1,4 @@ using System; -using ServiceControl.Operations; using ServiceControl.Persistence; using ServiceControl.Persistence.RavenDB.CustomChecks; diff --git a/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs b/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs index a8699d079c..433bbe6367 100644 --- a/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs +++ b/src/ServiceControl.Persistence.Tests.RavenDB/Archiving/ArchiveGroupTests.cs @@ -5,8 +5,6 @@ using Microsoft.Extensions.DependencyInjection; using NServiceBus.Testing; using NUnit.Framework; - using PersistenceTests; - using ServiceControl.Infrastructure.DomainEvents; using ServiceControl.Recoverability; [TestFixture] diff --git a/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs b/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs index cabc552742..1a8841b484 100644 --- a/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs +++ b/src/ServiceControl.Persistence.Tests/EnsureSettingsInContainer.cs @@ -9,7 +9,7 @@ public sealed class EnsureSettingsInContainer : PersistenceTestBase [Test] public void CheckForBothTypes() { - // Persistence implementation must register singleton as base type as some compoennts need to inject that + // Persistence implementation must register singleton as base type as some components need to inject that var baseSettings = ServiceProvider.GetRequiredService(); var actualType = baseSettings.GetType(); From 7ccb56473a527a27aea178f2d6076d6f95461d46 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Wed, 3 Apr 2024 16:17:17 -0400 Subject: [PATCH 10/14] Remove unneeded default setting in app.config --- src/ServiceControl/App.config | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ServiceControl/App.config b/src/ServiceControl/App.config index 2ffc12fdd6..b999c5b963 100644 --- a/src/ServiceControl/App.config +++ b/src/ServiceControl/App.config @@ -22,7 +22,6 @@ These settings are only here so that we can debug ServiceControl while developin - From e5be540f6b500e77f51c6f0e30553ab8da844640 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Wed, 3 Apr 2024 16:35:21 -0400 Subject: [PATCH 11/14] Use database path in exception messages --- .../CustomChecks/CheckFreeDiskSpace.cs | 4 ++-- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 6 +++--- .../CustomChecks/CheckFreeDiskSpace.cs | 4 ++-- .../CustomChecks/CheckMinimumStorageRequiredForIngestion.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index a1a98b86d9..18705af5b9 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -23,9 +23,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - if (dataPathRoot == null) + if (dataPathRoot is null) { - throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); + throw new Exception($"Unable to find the root of the data path {databaseConfiguration.ServerConfiguration.DbPath}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 4204b6d29e..e3803e5c3b 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -15,8 +15,8 @@ public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState state { this.stateHolder = stateHolder; this.databaseConfiguration = databaseConfiguration; - percentageThreshold = this.databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); + percentageThreshold = this.databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; } public override Task PerformCheck(CancellationToken cancellationToken = default) @@ -32,9 +32,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - if (dataPathRoot == null) + if (dataPathRoot is null) { - throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); + throw new Exception($"Unable to find the root of the data path {databaseConfiguration.ServerConfiguration.DbPath}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs index 0047a7ac35..c90bce9807 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckFreeDiskSpace.cs @@ -22,9 +22,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return CheckResult.Pass; } - if (dataPathRoot == null) + if (dataPathRoot is null) { - throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); + throw new Exception($"Unable to find the root of the data path {settings.DatabasePath}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index edde4d3ea8..69245774ab 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -32,9 +32,9 @@ public override Task PerformCheck(CancellationToken cancellationTok return SuccessResult; } - if (dataPathRoot == null) + if (dataPathRoot is null) { - throw new Exception($"Unable to find the root of the data path {dataPathRoot}"); + throw new Exception($"Unable to find the root of the data path {settings.DatabasePath}"); } var dataDriveInfo = new DriveInfo(dataPathRoot); From 06f6cba4d33b63a46b6cd5a6096b2b18a92e3585 Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Thu, 4 Apr 2024 14:48:10 -0400 Subject: [PATCH 12/14] Register audit custom checks manually in tests only to avoid double registration --- ...CustomChecksServiceCollectionExtensions.cs | 15 ------ .../RavenPersistence.cs | 5 -- .../PersistenceTestsConfiguration.cs | 19 ++++++- .../InMemory/PersistenceTestsConfiguration.cs | 50 ++++++++++++++----- ...viceControl.Audit.Persistence.Tests.csproj | 2 +- 5 files changed, 56 insertions(+), 35 deletions(-) delete mode 100644 src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs b/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs deleted file mode 100644 index 6a52393001..0000000000 --- a/src/ServiceControl.Audit.Persistence.RavenDB/InternalCustomChecksServiceCollectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ServiceControl.Audit.Persistence.RavenDB -{ - using Microsoft.Extensions.DependencyInjection; - using NServiceBus.CustomChecks; - - static class InternalCustomChecksServiceCollectionExtensions - { - public static void AddCustomCheck(this IServiceCollection serviceCollection) - where T : class, ICustomCheck - { - serviceCollection.AddTransient(); // Allows for T to have different instance registered for testing - serviceCollection.AddTransient(b => b.GetService()); - } - } -} \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs index 537a358aa7..75081a0547 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistence.cs @@ -1,6 +1,5 @@ namespace ServiceControl.Audit.Persistence.RavenDB { - using CustomChecks; using Microsoft.Extensions.DependencyInjection; using Persistence.UnitOfWork; using UnitOfWork; @@ -15,10 +14,6 @@ public void AddPersistence(IServiceCollection services) services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - - services.AddCustomCheck(); - services.AddCustomCheck(); - services.AddCustomCheck(); } public void AddInstaller(IServiceCollection services) => ConfigureLifecycle(services, databaseConfiguration); diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs index 1c8992367e..d45b4ec9d1 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/PersistenceTestsConfiguration.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using NServiceBus.CustomChecks; using NUnit.Framework; using Raven.Client.Documents; using Raven.Client.Documents.BulkInsert; @@ -16,19 +17,23 @@ class PersistenceTestsConfiguration { public IAuditDataStore AuditDataStore { get; private set; } + public IFailedAuditStorage FailedAuditStorage { get; private set; } + public IBodyStorage BodyStorage { get; private set; } + public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; private set; } + public IDocumentStore DocumentStore { get; private set; } + public IServiceProvider ServiceProvider => host.Services; + public string Name => "RavenDB"; public async Task Configure(Action setSettings) { var config = new RavenPersistenceConfiguration(); - var hostBuilder = Host.CreateApplicationBuilder(); - var persistenceSettings = new PersistenceSettings(TimeSpan.FromHours(1), true, 100000); setSettings(persistenceSettings); @@ -60,6 +65,16 @@ public async Task Configure(Action setSettings) persistence.AddPersistence(hostBuilder.Services); persistence.AddInstaller(hostBuilder.Services); + var assembly = typeof(RavenPersistenceConfiguration).Assembly; + + foreach (var type in assembly.DefinedTypes) + { + if (type.IsAssignableTo(typeof(ICustomCheck))) + { + hostBuilder.Services.AddTransient(typeof(ICustomCheck), type); + } + } + host = hostBuilder.Build(); await host.StartAsync(); diff --git a/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs b/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs index db46fbf2c0..4edecd97a8 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs +++ b/src/ServiceControl.Audit.Persistence.Tests/InMemory/PersistenceTestsConfiguration.cs @@ -4,38 +4,64 @@ using System.Threading.Tasks; using Auditing.BodyStorage; using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Hosting; + using NServiceBus.CustomChecks; using ServiceControl.Audit.Persistence.InMemory; using UnitOfWork; class PersistenceTestsConfiguration { public IAuditDataStore AuditDataStore { get; private set; } + public IFailedAuditStorage FailedAuditStorage { get; private set; } + public IBodyStorage BodyStorage { get; private set; } + public IAuditIngestionUnitOfWorkFactory AuditIngestionUnitOfWorkFactory { get; private set; } - public IServiceProvider ServiceProvider { get; private set; } + + public IServiceProvider ServiceProvider => host.Services; + public string Name => "InMemory"; - public Task Configure(Action setSettings) + public async Task Configure(Action setSettings) { var config = new InMemoryPersistenceConfiguration(); - var serviceCollection = new ServiceCollection(); + var hostBuilder = Host.CreateApplicationBuilder(); var settings = new PersistenceSettings(TimeSpan.FromHours(1), true, 100000); setSettings(settings); + var persistence = config.Create(settings); - persistence.AddPersistence(serviceCollection); - - ServiceProvider = serviceCollection.BuildServiceProvider(); - AuditDataStore = ServiceProvider.GetRequiredService(); - FailedAuditStorage = ServiceProvider.GetRequiredService(); - BodyStorage = ServiceProvider.GetService(); - AuditIngestionUnitOfWorkFactory = ServiceProvider.GetRequiredService(); - return Task.CompletedTask; + persistence.AddPersistence(hostBuilder.Services); + persistence.AddInstaller(hostBuilder.Services); + + var assembly = typeof(InMemoryPersistenceConfiguration).Assembly; + + foreach (var type in assembly.DefinedTypes) + { + if (type.IsAssignableTo(typeof(ICustomCheck))) + { + hostBuilder.Services.AddTransient(typeof(ICustomCheck), type); + } + } + + host = hostBuilder.Build(); + await host.StartAsync(); + + AuditDataStore = host.Services.GetRequiredService(); + FailedAuditStorage = host.Services.GetRequiredService(); + BodyStorage = host.Services.GetService(); + AuditIngestionUnitOfWorkFactory = host.Services.GetRequiredService(); } public Task CompleteDBOperation() => Task.CompletedTask; - public Task Cleanup() => Task.CompletedTask; + public async Task Cleanup() + { + await host.StopAsync(); + host.Dispose(); + } + + IHost host; } } \ No newline at end of file diff --git a/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj b/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj index 18062df884..3ccc7e39fc 100644 --- a/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj +++ b/src/ServiceControl.Audit.Persistence.Tests/ServiceControl.Audit.Persistence.Tests.csproj @@ -13,7 +13,7 @@ - + From a5eed165c2d6de4702e31327b9b40eff3d4bdece Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Thu, 4 Apr 2024 15:27:18 -0400 Subject: [PATCH 13/14] Adjust custom check to make it work with ATT hacks --- .../CheckMinimumStorageRequiredForIngestion.cs | 14 +++++--------- .../CheckMinimumStorageRequiredForIngestion.cs | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index e3803e5c3b..13b88ba3fe 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -15,27 +15,25 @@ public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState state { this.stateHolder = stateHolder; this.databaseConfiguration = databaseConfiguration; - dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath); - percentageThreshold = this.databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; } public override Task PerformCheck(CancellationToken cancellationToken = default) { + var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; + if (Logger.IsDebugEnabled) { Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); } - if (!databaseConfiguration.ServerConfiguration.UseEmbeddedServer) + // Should be checking UseEmbeddedServer but need to check DbPath instead for the ATT hack to work + if (string.IsNullOrEmpty(databaseConfiguration.ServerConfiguration.DbPath)) { stateHolder.CanIngestMore = true; return CheckResult.Pass; } - if (dataPathRoot is null) - { - throw new Exception($"Unable to find the root of the data path {databaseConfiguration.ServerConfiguration.DbPath}"); - } + var dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath) ?? throw new Exception($"Unable to find the root of the data path {databaseConfiguration.ServerConfiguration.DbPath}"); var dataDriveInfo = new DriveInfo(dataPathRoot); var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; @@ -100,8 +98,6 @@ public static int Parse(IDictionary settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - readonly string dataPathRoot; - readonly decimal percentageThreshold; readonly MinimumRequiredStorageState stateHolder; readonly DatabaseConfiguration databaseConfiguration; diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 69245774ab..716cbd102a 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -15,27 +15,25 @@ public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState state { this.stateHolder = stateHolder; this.settings = settings; - dataPathRoot = Path.GetPathRoot(settings.DatabasePath); - percentageThreshold = this.settings.MinimumStorageLeftRequiredForIngestion / 100m; } public override Task PerformCheck(CancellationToken cancellationToken = default) { + var percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; + if (Logger.IsDebugEnabled) { Logger.Debug($"Check ServiceControl data drive space starting. Threshold {percentageThreshold:P0}"); } - if (!settings.UseEmbeddedServer) + // Should be checking UseEmbeddedServer but need to check DatabasePath instead for the ATT hack to work + if (string.IsNullOrEmpty(settings.DatabasePath)) { stateHolder.CanIngestMore = true; return SuccessResult; } - if (dataPathRoot is null) - { - throw new Exception($"Unable to find the root of the data path {settings.DatabasePath}"); - } + var dataPathRoot = Path.GetPathRoot(settings.DatabasePath) ?? throw new Exception($"Unable to find the root of the data path {settings.DatabasePath}"); var dataDriveInfo = new DriveInfo(dataPathRoot); var availableFreeSpace = (decimal)dataDriveInfo.AvailableFreeSpace; @@ -82,8 +80,6 @@ public static void Validate(RavenPersisterSettings settings) public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - readonly string dataPathRoot; - readonly decimal percentageThreshold; readonly MinimumRequiredStorageState stateHolder; readonly RavenPersisterSettings settings; From 84926fdbd7460e4dad810ace982de1da887748ae Mon Sep 17 00:00:00 2001 From: Brandon Ording Date: Thu, 4 Apr 2024 15:35:58 -0400 Subject: [PATCH 14/14] Cleanup and unify implementations --- ...CheckMinimumStorageRequiredForIngestion.cs | 36 ++++++------------- ...CheckMinimumStorageRequiredForIngestion.cs | 19 +++------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 13b88ba3fe..6d2fccbc38 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -9,14 +9,8 @@ using NServiceBus.Logging; using RavenDB; - class CheckMinimumStorageRequiredForIngestion : CustomCheck + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration) : CustomCheck("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) { - public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, DatabaseConfiguration databaseConfiguration) : base("Audit Message Ingestion Process", "ServiceControl.Audit Health", TimeSpan.FromSeconds(5)) - { - this.stateHolder = stateHolder; - this.databaseConfiguration = databaseConfiguration; - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = databaseConfiguration.MinimumStorageLeftRequiredForIngestion / 100m; @@ -30,7 +24,7 @@ public override Task PerformCheck(CancellationToken cancellationTok if (string.IsNullOrEmpty(databaseConfiguration.ServerConfiguration.DbPath)) { stateHolder.CanIngestMore = true; - return CheckResult.Pass; + return SuccessResult; } var dataPathRoot = Path.GetPathRoot(databaseConfiguration.ServerConfiguration.DbPath) ?? throw new Exception($"Unable to find the root of the data path {databaseConfiguration.ServerConfiguration.DbPath}"); @@ -43,18 +37,16 @@ public override Task PerformCheck(CancellationToken cancellationTok if (Logger.IsDebugEnabled) { - Logger.Debug( - $"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); + Logger.Debug($"Free space: {availableFreeSpace} | Total: {totalSpace} | Percent remaining {percentRemaining:P0}"); } if (percentRemaining > percentageThreshold) { stateHolder.CanIngestMore = true; - return CheckResult.Pass; + return SuccessResult; } - var message = - $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; + var message = $"Audit message ingestion stopped! {percentRemaining:P0} disk space remaining on data drive '{dataDriveInfo.VolumeLabel} ({dataDriveInfo.RootDirectory})' on '{Environment.MachineName}'. This is less than {percentageThreshold}% - the minimal required space configured. The threshold can be set using the {RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} configuration setting."; Logger.Warn(message); stateHolder.CanIngestMore = false; return CheckResult.Failed(message); @@ -62,33 +54,28 @@ public override Task PerformCheck(CancellationToken cancellationTok public static int Parse(IDictionary settings) { - if (!settings.TryGetValue(RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey, - out var thresholdValue)) + if (!settings.TryGetValue(RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey, out var thresholdValue)) { thresholdValue = $"{MinimumStorageLeftRequiredForIngestionDefault}"; } - string message; if (!int.TryParse(thresholdValue, out var threshold)) { - message = - $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; + var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} must be an integer."; Logger.Fatal(message); throw new Exception(message); } if (threshold < 0) { - message = - $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; + var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; Logger.Fatal(message); throw new Exception(message); } if (threshold > 100) { - message = - $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; + var message = $"{RavenPersistenceConfiguration.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; Logger.Fatal(message); throw new Exception(message); } @@ -97,10 +84,7 @@ public static int Parse(IDictionary settings) } public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - - readonly MinimumRequiredStorageState stateHolder; - readonly DatabaseConfiguration databaseConfiguration; - + static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); } } \ No newline at end of file diff --git a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs index 716cbd102a..053a41cff7 100644 --- a/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs +++ b/src/ServiceControl.Persistence.RavenDB/CustomChecks/CheckMinimumStorageRequiredForIngestion.cs @@ -9,14 +9,8 @@ using ServiceControl.Persistence; using ServiceControl.Persistence.RavenDB; - class CheckMinimumStorageRequiredForIngestion : CustomCheck + class CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings) : CustomCheck("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) { - public CheckMinimumStorageRequiredForIngestion(MinimumRequiredStorageState stateHolder, RavenPersisterSettings settings) : base("Message Ingestion Process", "ServiceControl Health", TimeSpan.FromSeconds(5)) - { - this.stateHolder = stateHolder; - this.settings = settings; - } - public override Task PerformCheck(CancellationToken cancellationToken = default) { var percentageThreshold = settings.MinimumStorageLeftRequiredForIngestion / 100m; @@ -60,29 +54,24 @@ public override Task PerformCheck(CancellationToken cancellationTok public static void Validate(RavenPersisterSettings settings) { - int threshold = settings.MinimumStorageLeftRequiredForIngestion; + var threshold = settings.MinimumStorageLeftRequiredForIngestion; - string message; if (threshold < 0) { - message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; + var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, minimum value is 0."; Logger.Fatal(message); throw new Exception(message); } if (threshold > 100) { - message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; + var message = $"{RavenBootstrapper.MinimumStorageLeftRequiredForIngestionKey} is invalid, maximum value is 100."; Logger.Fatal(message); throw new Exception(message); } } public const int MinimumStorageLeftRequiredForIngestionDefault = 5; - - readonly MinimumRequiredStorageState stateHolder; - readonly RavenPersisterSettings settings; - static readonly Task SuccessResult = Task.FromResult(CheckResult.Pass); static readonly ILog Logger = LogManager.GetLogger(typeof(CheckMinimumStorageRequiredForIngestion)); }