Skip to content

Commit

Permalink
Report both CPU and Memory issues
Browse files Browse the repository at this point in the history
  • Loading branch information
willibrandon committed Sep 7, 2024
1 parent 858624b commit bafe01a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Diagnostics.ResourceMonitoring;
Expand All @@ -14,7 +15,6 @@ namespace Microsoft.Extensions.Diagnostics.HealthChecks;
/// </summary>
internal sealed class ResourceUtilizationHealthCheck : IHealthCheck
{
private static readonly Task<HealthCheckResult> _healthy = Task.FromResult(HealthCheckResult.Healthy());
private readonly ResourceUtilizationHealthCheckOptions _options;
private readonly IResourceMonitor _dataTracker;

Expand All @@ -39,26 +39,36 @@ public ResourceUtilizationHealthCheck(IOptions<ResourceUtilizationHealthCheckOpt
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
var utilization = _dataTracker.GetUtilization(_options.SamplingWindow);
if (utilization.CpuUsedPercentage > _options.CpuThresholds.UnhealthyUtilizationPercentage)
IReadOnlyDictionary<string, object> data = new Dictionary<string, object>
{
return Task.FromResult(HealthCheckResult.Unhealthy("CPU usage is above the limit"));
}
{ nameof(utilization.CpuUsedPercentage), utilization.CpuUsedPercentage },
{ nameof(utilization.MemoryUsedPercentage), utilization.MemoryUsedPercentage },
};

if (utilization.MemoryUsedPercentage > _options.MemoryThresholds.UnhealthyUtilizationPercentage)
if (utilization.CpuUsedPercentage > _options.CpuThresholds.UnhealthyUtilizationPercentage)
{
return Task.FromResult(HealthCheckResult.Unhealthy("Memory usage is above the limit"));
string message = "CPU usage is above the limit";

if (utilization.MemoryUsedPercentage > _options.MemoryThresholds.UnhealthyUtilizationPercentage)
{
message = "CPU and Memory usage is above the limit";
}

return Task.FromResult(HealthCheckResult.Unhealthy(message, default, data));
}

if (utilization.CpuUsedPercentage > _options.CpuThresholds.DegradedUtilizationPercentage)
{
return Task.FromResult(HealthCheckResult.Degraded("CPU usage is close to the limit"));
}
string message = "CPU usage is close to the limit";

if (utilization.MemoryUsedPercentage > _options.MemoryThresholds.DegradedUtilizationPercentage)
{
return Task.FromResult(HealthCheckResult.Degraded("Memory usage is close to the limit"));
if (utilization.MemoryUsedPercentage > _options.MemoryThresholds.DegradedUtilizationPercentage)
{
message = "CPU and Memory usage is close to the limit";
}

return Task.FromResult(HealthCheckResult.Degraded(message, default, data));
}

return _healthy;
return Task.FromResult(HealthCheckResult.Healthy(default, data));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,61 +92,31 @@ public class ResourceHealthCheckTests

[Theory]
[MemberData(nameof(Data))]
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
public async Task TestCpuChecks(HealthStatus expected, double utilization, ulong _, ulong totalMemory, ResourceUsageThresholds thresholds, string expectedDescription)
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
public async Task TestCpuAndMemoryChecks(HealthStatus expected, double utilization, ulong memoryUsed, ulong totalMemory, ResourceUsageThresholds thresholds, string expectedDescription)
{
var systemResources = new SystemResources(1.0, 1.0, totalMemory, totalMemory);
var dataTracker = new Mock<IResourceMonitor>();
var samplingWindow = TimeSpan.FromSeconds(1);
dataTracker
.Setup(tracker => tracker.GetUtilization(samplingWindow))
.Returns(new ResourceUtilization(cpuUsedPercentage: utilization, memoryUsedInBytes: 0, systemResources));
.Returns(new ResourceUtilization(cpuUsedPercentage: utilization, memoryUsedInBytes: memoryUsed, systemResources));

var checkContext = new HealthCheckContext();
var cpuCheckOptions = new ResourceUtilizationHealthCheckOptions
{
CpuThresholds = thresholds,
SamplingWindow = samplingWindow
};

var options = Microsoft.Extensions.Options.Options.Create(cpuCheckOptions);
var healthCheck = new ResourceUtilizationHealthCheck(options, dataTracker.Object);
var healthCheckResult = await healthCheck.CheckHealthAsync(checkContext);
Assert.Equal(expected, healthCheckResult.Status);
if (healthCheckResult.Status != HealthStatus.Healthy)
{
Assert.Equal("CPU" + expectedDescription, healthCheckResult.Description);
}
}

[Theory]
[MemberData(nameof(Data))]
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
public async Task TestMemoryChecks(HealthStatus expected, double _, ulong memoryUsed, ulong totalMemory, ResourceUsageThresholds thresholds, string expectedDescription)
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
{
var systemResources = new SystemResources(1.0, 1.0, totalMemory, totalMemory);
var dataTracker = new Mock<IResourceMonitor>();
var samplingWindow = TimeSpan.FromSeconds(1);
dataTracker
.Setup(tracker => tracker.GetUtilization(samplingWindow))
.Returns(new ResourceUtilization(cpuUsedPercentage: 0, memoryUsedInBytes: memoryUsed, systemResources));

var checkContext = new HealthCheckContext();
var memCheckOptions = new ResourceUtilizationHealthCheckOptions
{
MemoryThresholds = thresholds,
SamplingWindow = samplingWindow
};

var options = Microsoft.Extensions.Options.Options.Create(memCheckOptions);
var options = Microsoft.Extensions.Options.Options.Create(cpuCheckOptions);
var healthCheck = new ResourceUtilizationHealthCheck(options, dataTracker.Object);
var healthCheckResult = await healthCheck.CheckHealthAsync(checkContext);
Assert.Equal(expected, healthCheckResult.Status);
Assert.NotEmpty(healthCheckResult.Data);
if (healthCheckResult.Status != HealthStatus.Healthy)
{
Assert.Equal("Memory" + expectedDescription, healthCheckResult.Description);
Assert.Equal("CPU and Memory" + expectedDescription, healthCheckResult.Description);
}
}

Expand Down

0 comments on commit bafe01a

Please sign in to comment.