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 3081699065..c6c3016d0a 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) { @@ -26,6 +27,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 } } diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs b/src/ServiceControl.Audit.Persistence.RavenDB/RavenPersistenceConfiguration.cs index 0f227d5906..9cbc09b7a1 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 @@ -16,6 +17,7 @@ public class RavenPersistenceConfiguration : IPersistenceConfiguration public const string LogPathKey = "LogPath"; public const string RavenDbLogLevelKey = "RavenDBLogLevel"; public const string MinimumStorageLeftRequiredForIngestionKey = "MinimumStorageLeftRequiredForIngestion"; + public const string DataSpaceRemainingThresholdKey = "DataSpaceRemainingThreshold"; public IEnumerable ConfigurationKeys => new[]{ DatabaseNameKey, @@ -25,6 +27,7 @@ public class RavenPersistenceConfiguration : IPersistenceConfiguration ExpirationProcessTimerInSecondsKey, LogPathKey, RavenDbLogLevelKey, + DataSpaceRemainingThresholdKey, MinimumStorageLeftRequiredForIngestionKey }; @@ -89,15 +92,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); @@ -107,6 +103,7 @@ internal static DatabaseConfiguration GetDatabaseConfiguration(PersistenceSettin settings.EnableFullTextSearchOnBodies, settings.AuditRetentionPeriod, settings.MaxBodySizeToStore, + dataSpaceRemainingThreshold, minimumStorageLeftRequiredForIngestion, serverConfiguration); } diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs index 97a87dbae9..0dfcee2373 100644 --- a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/SharedEmbeddedServer.cs @@ -33,7 +33,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))); + embeddedDatabase = EmbeddedDatabase.Start(new DatabaseConfiguration("audit", 60, true, TimeSpan.FromMinutes(5), 120000, 5, 5, new ServerConfiguration(dbPath, serverUrl, logPath, logsMode))); //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 5739f5dc9d..dae685ddbe 100644 --- a/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.Audit.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -20,7 +20,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 9cffda9c3e..5fca1fcfcb 100644 --- a/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl.Audit/Infrastructure/Settings/Settings.cs @@ -35,7 +35,6 @@ public Settings(string serviceName, string transportType = null, string persiste 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); @@ -132,8 +131,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; } @@ -264,27 +261,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"); ILog logger = LogManager.GetLogger(typeof(Settings)); @@ -293,6 +269,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 a345c39fa4..fcb94c2643 100644 --- a/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt +++ b/src/ServiceControl.UnitTests/ApprovalFiles/APIApprovals.PlatformSampleSettings.approved.txt @@ -36,6 +36,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 adb3442378..e7697a7053 100644 --- a/src/ServiceControl/Infrastructure/Settings/Settings.cs +++ b/src/ServiceControl/Infrastructure/Settings/Settings.cs @@ -52,7 +52,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); } @@ -164,8 +163,6 @@ public TimeSpan HeartbeatGracePeriod public RemoteInstanceSetting[] RemoteInstances { get; set; } - public int DataSpaceRemainingThreshold { get; set; } - public bool DisableHealthChecks { get; set; } public ITransportCustomization LoadTransportCustomization() @@ -370,27 +367,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"); @@ -422,7 +398,5 @@ void LoadErrorIngestionSettings() static readonly ILog logger = LogManager.GetLogger(typeof(Settings)); 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