Skip to content

Commit 73c593e

Browse files
committed
Allow enable/disable service/admin health checks
Signed-off-by: Victor Chang <[email protected]>
1 parent f80eb92 commit 73c593e

File tree

5 files changed

+130
-30
lines changed

5 files changed

+130
-30
lines changed

src/Plugins/MinIO/HealthCheckBuilder.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,7 @@ namespace Monai.Deploy.Storage.MinIO
2323
{
2424
public class HealthCheckBuilder : HealthCheckRegistrationBase
2525
{
26-
public override IHealthChecksBuilder Configure(
27-
IHealthChecksBuilder builder,
28-
HealthStatus? failureStatus = null,
29-
IEnumerable<string>? tags = null,
30-
TimeSpan? timeout = null)
31-
{
26+
public override IHealthChecksBuilder ConfigureAdminHealthCheck(IHealthChecksBuilder builder, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) =>
3227
builder.Add(new HealthCheckRegistration(
3328
ConfigurationKeys.StorageServiceName,
3429
serviceProvider =>
@@ -41,6 +36,7 @@ public override IHealthChecksBuilder Configure(
4136
tags,
4237
timeout));
4338

39+
public override IHealthChecksBuilder ConfigureHealthCheck(IHealthChecksBuilder builder, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) =>
4440
builder.Add(new HealthCheckRegistration(
4541
$"{ConfigurationKeys.StorageServiceName}-admin",
4642
serviceProvider =>
@@ -52,8 +48,5 @@ public override IHealthChecksBuilder Configure(
5248
failureStatus,
5349
tags,
5450
timeout));
55-
56-
return builder;
57-
}
5851
}
5952
}

src/Plugins/MinIO/Tests/ServiceRegistrationTest.cs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Reflection;
1919
using Microsoft.Extensions.DependencyInjection;
2020
using Microsoft.Extensions.Diagnostics.HealthChecks;
21+
using Microsoft.Extensions.Options;
2122
using Moq;
2223
using Xunit;
2324

@@ -46,32 +47,66 @@ public void AddMonaiDeployStorageService_WhenCalled_RegisterServicesOnly()
4647
var serviceCollection = new Mock<IServiceCollection>();
4748
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
4849

49-
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, false);
50+
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, HealthCheckOptions.None);
5051

5152
Assert.Same(serviceCollection.Object, returnedServiceCollection);
5253

5354
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.Exactly(4));
5455
}
5556

5657
[Fact]
57-
public void AddMonaiDeployStorageService_WhenCalled_RegisterServicesAndHealthChecks()
58+
public void AddMonaiDeployStorageService_WhenCalled_RegisterServicesAndServiceHealthCheck()
59+
{
60+
var serviceCollection = new Mock<IServiceCollection>();
61+
62+
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
63+
serviceCollection.Setup(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))));
64+
65+
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, HealthCheckOptions.ServiceHealthCheck);
66+
Assert.Same(serviceCollection.Object, returnedServiceCollection);
67+
68+
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.AtLeast(5));
69+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))), Times.Once());
70+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(IConfigureOptions<HealthCheckServiceOptions>))), Times.Once());
71+
}
72+
73+
[Fact]
74+
public void AddMonaiDeployStorageService_WhenCalled_RegisterServicesAndHealthCheck()
5875
{
5976
var serviceCollection = new Mock<IServiceCollection>();
77+
6078
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
79+
serviceCollection.Setup(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))));
6180

62-
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, true);
81+
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, HealthCheckOptions.AdminServiceHealthCheck);
82+
Assert.Same(serviceCollection.Object, returnedServiceCollection);
83+
84+
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.AtLeast(5));
85+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))), Times.Once());
86+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(IConfigureOptions<HealthCheckServiceOptions>))), Times.Once());
87+
}
88+
89+
[Fact]
90+
public void AddMonaiDeployStorageService_WhenCalled_RegisterServicesAndHealthChecks()
91+
{
92+
var serviceCollection = new Mock<IServiceCollection>();
6393

94+
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
95+
serviceCollection.Setup(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))));
96+
97+
var returnedServiceCollection = serviceCollection.Object.AddMonaiDeployStorageService(_type.AssemblyQualifiedName, _fileSystem, HealthCheckOptions.ServiceHealthCheck | HealthCheckOptions.AdminServiceHealthCheck);
6498
Assert.Same(serviceCollection.Object, returnedServiceCollection);
6599

66100
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.AtLeast(5));
67101
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))), Times.Once());
102+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(IConfigureOptions<HealthCheckServiceOptions>))), Times.Exactly(2));
68103
}
69104

70105
private static byte[] GetAssemblyeBytes(Assembly assembly)
71106
{
72107
return File.ReadAllBytes(assembly.Location);
73108
}
74109
}
110+
}
75111

76112
#pragma warning restore CS8604 // Possible null reference argument.
77-
}

src/Storage/HealthCheckRegistrationBase.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ namespace Monai.Deploy.Storage
2121
{
2222
public abstract class HealthCheckRegistrationBase
2323
{
24-
public abstract IHealthChecksBuilder Configure(
24+
public abstract IHealthChecksBuilder ConfigureHealthCheck(
25+
IHealthChecksBuilder builder,
26+
HealthStatus? failureStatus = null,
27+
IEnumerable<string>? tags = null,
28+
TimeSpan? timeout = null);
29+
30+
public abstract IHealthChecksBuilder ConfigureAdminHealthCheck(
2531
IHealthChecksBuilder builder,
2632
HealthStatus? failureStatus = null,
2733
IEnumerable<string>? tags = null,

src/Storage/IServiceCollectionExtension.cs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424

2525
namespace Monai.Deploy.Storage
2626
{
27+
[Flags]
28+
public enum HealthCheckOptions
29+
{
30+
None = 0,
31+
ServiceHealthCheck = 1,
32+
AdminServiceHealthCheck = 2,
33+
}
34+
2735
public static class IServiceCollectionExtensions
2836
{
2937
/// <summary>
@@ -36,11 +44,11 @@ public static class IServiceCollectionExtensions
3644
public static IServiceCollection AddMonaiDeployStorageService(
3745
this IServiceCollection services,
3846
string fullyQualifiedTypeName,
39-
bool registerHealthCheck = true,
47+
HealthCheckOptions healthCheckOptions = HealthCheckOptions.ServiceHealthCheck & HealthCheckOptions.AdminServiceHealthCheck,
4048
HealthStatus? failureStatus = null,
4149
IEnumerable<string>? tags = null,
4250
TimeSpan? timeout = null)
43-
=> AddMonaiDeployStorageService(services, fullyQualifiedTypeName, new FileSystem(), registerHealthCheck, failureStatus, tags, timeout);
51+
=> AddMonaiDeployStorageService(services, fullyQualifiedTypeName, new FileSystem(), healthCheckOptions, failureStatus, tags, timeout);
4452

4553
/// <summary>
4654
/// Configures all dependencies required for the MONAI Deploy Storage Service.
@@ -54,7 +62,7 @@ public static IServiceCollection AddMonaiDeployStorageService(
5462
this IServiceCollection services,
5563
string fullyQualifiedTypeName,
5664
IFileSystem fileSystem,
57-
bool registerHealthCheck = true,
65+
HealthCheckOptions healthCheckOptions = HealthCheckOptions.ServiceHealthCheck & HealthCheckOptions.AdminServiceHealthCheck,
5866
HealthStatus? failureStatus = null,
5967
IEnumerable<string>? tags = null,
6068
TimeSpan? timeout = null)
@@ -78,23 +86,26 @@ public static IServiceCollection AddMonaiDeployStorageService(
7886

7987
RegisterServices(services, fullyQualifiedTypeName, storageServiceAssembly);
8088

81-
if (registerHealthCheck)
82-
{
83-
RegisterHealtChecks(services, fullyQualifiedTypeName, storageServiceAssembly, failureStatus, tags, timeout);
84-
}
89+
RegisterHealtChecks(healthCheckOptions, services, fullyQualifiedTypeName, storageServiceAssembly, failureStatus, tags, timeout);
8590

8691
AppDomain.CurrentDomain.AssemblyResolve -= resolveEventHandler;
8792
return services;
8893
}
8994

9095
private static void RegisterHealtChecks(
96+
HealthCheckOptions healthCheckOptions,
9197
IServiceCollection services,
9298
string fullyQualifiedTypeName,
9399
Assembly storageServiceAssembly,
94100
HealthStatus? failureStatus = null,
95101
IEnumerable<string>? tags = null,
96102
TimeSpan? timeout = null)
97103
{
104+
if (healthCheckOptions == HealthCheckOptions.None)
105+
{
106+
return;
107+
}
108+
98109
var healthCheckBase = storageServiceAssembly.GetTypes().FirstOrDefault(p => p.IsSubclassOf(typeof(HealthCheckRegistrationBase)));
99110

100111
if (healthCheckBase is null || Activator.CreateInstance(healthCheckBase) is not HealthCheckRegistrationBase healthCheckBuilderBase)
@@ -103,7 +114,16 @@ private static void RegisterHealtChecks(
103114
}
104115

105116
var healthCheckBuilder = services.AddHealthChecks();
106-
healthCheckBuilderBase.Configure(healthCheckBuilder, failureStatus, tags, timeout);
117+
118+
if (healthCheckOptions.HasFlag(HealthCheckOptions.ServiceHealthCheck))
119+
{
120+
healthCheckBuilderBase.ConfigureHealthCheck(healthCheckBuilder, failureStatus, tags, timeout);
121+
}
122+
123+
if (healthCheckOptions.HasFlag(HealthCheckOptions.AdminServiceHealthCheck))
124+
{
125+
healthCheckBuilderBase.ConfigureAdminHealthCheck(healthCheckBuilder, failureStatus, tags, timeout);
126+
}
107127
}
108128

109129
private static void RegisterServices(IServiceCollection services, string fullyQualifiedTypeName, Assembly storageServiceAssembly)

src/Storage/Tests/IServiceCollectionExtensionsTests.cs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,15 @@ public void AddMonaiDeployStorageService_ConfiuresServicesAsExpected()
101101
fileSystem.File.WriteAllBytes(assemblyFilePath, assemblyData);
102102
var serviceCollection = new Mock<IServiceCollection>();
103103
serviceCollection.Setup(p => p.Clear());
104-
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, false));
104+
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, HealthCheckOptions.None));
105105

106106
Assert.Null(exception);
107107

108108
serviceCollection.Verify(p => p.Clear(), Times.Once());
109109
}
110110

111-
[Fact(DisplayName = "AddMonaiDeployStorageService configures all services & health checks as expected")]
112-
public void AddMonaiDeployStorageService_ConfiuresServicesAndHealtChecksAsExpected()
111+
[Fact(DisplayName = "AddMonaiDeployStorageService configures all services & service health check as expected")]
112+
public void AddMonaiDeployStorageService_ConfiuresServicesAndServiceHealtCheckAsExpected()
113113
{
114114
var goodType = typeof(GoodStorageService);
115115
var typeName = goodType.AssemblyQualifiedName;
@@ -123,14 +123,61 @@ public void AddMonaiDeployStorageService_ConfiuresServicesAndHealtChecksAsExpect
123123
serviceCollection.Setup(p => p.Clear());
124124
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
125125

126-
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, true));
126+
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, HealthCheckOptions.ServiceHealthCheck));
127127

128128
Assert.Null(exception);
129129

130130
serviceCollection.Verify(p => p.Clear(), Times.Once());
131131
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.Exactly(2));
132132
}
133133

134+
[Fact(DisplayName = "AddMonaiDeployStorageService configures all services & admin health check as expected")]
135+
public void AddMonaiDeployStorageService_ConfiuresServicesAndAdminHealthCheckAsExpected()
136+
{
137+
var goodType = typeof(GoodStorageService);
138+
var typeName = goodType.AssemblyQualifiedName;
139+
var assemblyData = GetAssemblyeBytes(goodType.Assembly);
140+
var assemblyFilePath = Path.Combine(SR.PlugInDirectoryPath, goodType.Assembly.ManifestModule.Name);
141+
var fileSystem = new MockFileSystem();
142+
fileSystem.Directory.CreateDirectory(SR.PlugInDirectoryPath);
143+
fileSystem.File.WriteAllBytes(assemblyFilePath, assemblyData);
144+
145+
var serviceCollection = new Mock<IServiceCollection>();
146+
serviceCollection.Setup(p => p.Clear());
147+
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
148+
149+
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, HealthCheckOptions.AdminServiceHealthCheck));
150+
151+
Assert.Null(exception);
152+
153+
serviceCollection.Verify(p => p.Clear(), Times.Once());
154+
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.Exactly(2));
155+
}
156+
157+
[Fact(DisplayName = "AddMonaiDeployStorageService configures all services & all health checks as expected")]
158+
public void AddMonaiDeployStorageService_ConfiuresServicesAndAllHealtCheckAsExpected()
159+
{
160+
var goodType = typeof(GoodStorageService);
161+
var typeName = goodType.AssemblyQualifiedName;
162+
var assemblyData = GetAssemblyeBytes(goodType.Assembly);
163+
var assemblyFilePath = Path.Combine(SR.PlugInDirectoryPath, goodType.Assembly.ManifestModule.Name);
164+
var fileSystem = new MockFileSystem();
165+
fileSystem.Directory.CreateDirectory(SR.PlugInDirectoryPath);
166+
fileSystem.File.WriteAllBytes(assemblyFilePath, assemblyData);
167+
168+
var serviceCollection = new Mock<IServiceCollection>();
169+
serviceCollection.Setup(p => p.Clear());
170+
serviceCollection.Setup(p => p.Add(It.IsAny<ServiceDescriptor>()));
171+
172+
var exception = Record.Exception(() => serviceCollection.Object.AddMonaiDeployStorageService(typeName, fileSystem, HealthCheckOptions.ServiceHealthCheck | HealthCheckOptions.AdminServiceHealthCheck));
173+
174+
Assert.Null(exception);
175+
176+
serviceCollection.Verify(p => p.Clear(), Times.Once());
177+
serviceCollection.Verify(p => p.Add(It.IsAny<ServiceDescriptor>()), Times.Exactly(2));
178+
serviceCollection.Verify(p => p.Add(It.Is<ServiceDescriptor>(p => p.ServiceType == typeof(HealthCheckService))), Times.Once());
179+
}
180+
134181
private static byte[] GetAssemblyeBytes(Assembly assembly)
135182
{
136183
return File.ReadAllBytes(assembly.Location);
@@ -139,10 +186,9 @@ private static byte[] GetAssemblyeBytes(Assembly assembly)
139186

140187
internal class TestHealthCheckRegistrar : HealthCheckRegistrationBase
141188
{
142-
public override IHealthChecksBuilder Configure(IHealthChecksBuilder builder, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null)
143-
{
144-
return builder;
145-
}
189+
public override IHealthChecksBuilder ConfigureAdminHealthCheck(IHealthChecksBuilder builder, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) => builder;
190+
191+
public override IHealthChecksBuilder ConfigureHealthCheck(IHealthChecksBuilder builder, HealthStatus? failureStatus = null, IEnumerable<string>? tags = null, TimeSpan? timeout = null) => builder;
146192
}
147193

148194
internal class TestServiceRegistrar : ServiceRegistrationBase

0 commit comments

Comments
 (0)