Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 78 additions & 8 deletions src/ServiceControl.Transports.Msmq/CheckDeadLetterQueue.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace ServiceControl.MSMQ.DLQMonitor
{
using System;
using System.Configuration;
using System.Diagnostics;
using System.Threading.Tasks;
using NServiceBus.CustomChecks;
Expand All @@ -13,31 +14,100 @@ public CheckDeadLetterQueue() :
{
Logger.Debug("MSMQ Dead Letter Queue custom check starting");

dlqPerformanceCounter = new PerformanceCounter(
categoryName: "MSMQ Queue",
counterName: "Messages in Queue",
instanceName: "Computer Queues",
readOnly: true);
categoryName = Read("Msmq/PerformanceCounterCategoryName", "MSMQ Queue");
counterName = Read("Msmq/PerformanceCounterName", "Messages in Queue");
counterInstanceName = Read("Msmq/PerformanceCounterInstanceName", "Computer Queues");

try
{
dlqPerformanceCounter = new PerformanceCounter(categoryName, counterName, counterInstanceName, readOnly: true);
}
catch (InvalidOperationException ex)
{
Logger.Error(CounterMightBeLocalized(categoryName, counterName, counterInstanceName), ex);
}
}

public override Task<CheckResult> PerformCheck()
{
Logger.Debug("Checking Dead Letter Queue length");
var currentValue = dlqPerformanceCounter.NextValue();
float currentValue;
string result;
try
{
if (dlqPerformanceCounter == null)
{
throw new InvalidOperationException("Unable to create performance counter instance.");
}

currentValue = dlqPerformanceCounter.NextValue();
}
catch (InvalidOperationException ex)
{
result = CounterMightBeLocalized(categoryName, counterName, counterInstanceName);
Logger.Warn(result, ex);
return CheckResult.Failed(result);
}

if (currentValue <= 0)
{
Logger.Debug("No messages in Dead Letter Queue");
return CheckResult.Pass;
}

var result = $"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular using support@particular.net if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.";

result = MessagesInDeadLetterQueue(currentValue);
Logger.Warn(result);
return CheckResult.Failed(result);
}

static string MessagesInDeadLetterQueue(float currentValue)
{
return $"{currentValue} messages in the Dead Letter Queue on {Environment.MachineName}. This could indicate a problem with ServiceControl's retries. Please submit a support ticket to Particular using support@particular.net if you would like help from our engineers to ensure no message loss while resolving these dead letter messages.";
}

static string CounterMightBeLocalized(string categoryName, string counterName, string counterInstanceName)
{
return
$"Unable to read the Dead Letter Queue length. The performance counter with category '{categoryName}' and name '{counterName}' and instance name '{counterInstanceName}' is not available. "
+ "It is possible that the counter category, name and instance name have been localized into different languages. "
+ @"Consider overriding the counter category, name and instance name in the application configuration file by adding:
<appSettings>
<add key=""ServiceControl/Msmq/PerformanceCounterCategoryName"" value=""LocalizedCategoryName"" />
<add key=""ServiceControl/Msmq/PerformanceCounterName"" value=""LocalizedCounterName"" />
<add key=""ServiceControl/Msmq/PerformanceCounterInstanceName"" value=""LocalizedCounterInstanceName"" />
</appSettings>
";
}

// from ConfigFileSettingsReader since we cannot reference ServiceControl
static string Read(string name, string defaultValue = default)
{
return Read("ServiceControl", name, defaultValue);
}

static string Read(string root, string name, string defaultValue = default)
{
return TryRead(root, name, out var value) ? value : defaultValue;
}

static bool TryRead(string root, string name, out string value)
{
var fullKey = $"{root}/{name}";

if (ConfigurationManager.AppSettings[fullKey] != null)
{
value = ConfigurationManager.AppSettings[fullKey];
return true;
}

value = default;
return false;
}

PerformanceCounter dlqPerformanceCounter;
private string categoryName;
private string counterName;
private string counterInstanceName;

static readonly ILog Logger = LogManager.GetLogger(typeof(CheckDeadLetterQueue));
}
Expand Down