Skip to content

Commit 1ebfa37

Browse files
authored
Merge pull request #475 from aurelianware/claude/add-health-checks-BIJt1
2 parents d2ebd2d + c6677c5 commit 1ebfa37

File tree

67 files changed

+829
-355
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+829
-355
lines changed

.github/workflows/docker-build.yml

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,13 @@ jobs:
4848
- claims-scrubbing-service
4949
- enrollment-import-service
5050
- trading-partner-service
51+
- tenant-service
52+
- benefit-plan-service
53+
- payment-service
5154
include:
52-
# tenant-service needs repo root as context so it can reach scripts/setup/
53-
- service: tenant-service
54-
build_context: '.'
55-
# benefit-plan-service references CloudHealthOffice.BenefitEngine (../../engines/...)
56-
# so the build context must be the repo root
57-
- service: benefit-plan-service
58-
build_context: '.'
59-
# attachment-service references CloudHealthOffice.DocumentStore (../../engines/...)
60-
# so the build context must be the repo root
61-
- service: attachment-service
62-
build_context: '.'
63-
# claims-service references CloudHealthOffice.Infrastructure (../shared/...)
64-
# so the build context must be the repo root
65-
- service: claims-service
66-
build_context: '.'
55+
# claims-scrubbing-service is Node.js — its Dockerfile uses service-local paths
56+
- service: claims-scrubbing-service
57+
build_context: './src/services/claims-scrubbing-service'
6758
steps:
6859
- name: Checkout code
6960
uses: actions/checkout@v4
@@ -95,7 +86,7 @@ jobs:
9586
- name: Build and push
9687
uses: docker/build-push-action@v5
9788
with:
98-
context: ${{ matrix.build_context || format('./src/services/{0}', matrix.service) }}
89+
context: ${{ matrix.build_context || '.' }}
9990
file: ./src/services/${{ matrix.service }}/Dockerfile
10091
push: ${{ github.event_name != 'pull_request' }}
10192
tags: ${{ steps.meta.outputs.tags }}

docker-compose.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ services:
3636

3737
claims-service:
3838
build:
39-
context: src/services/claims-service
40-
dockerfile: Dockerfile
39+
context: .
40+
dockerfile: src/services/claims-service/Dockerfile
4141
ports:
4242
- "5001:8080"
4343
environment:
@@ -48,7 +48,7 @@ services:
4848
mongo:
4949
condition: service_healthy
5050
healthcheck:
51-
test: ["CMD-SHELL", "curl -f http://localhost:8080/health || exit 1"]
51+
test: ["CMD-SHELL", "curl -f http://localhost:8080/health/live || exit 1"]
5252
interval: 10s
5353
timeout: 5s
5454
retries: 10
@@ -75,8 +75,8 @@ services:
7575

7676
payment-service:
7777
build:
78-
context: src/services/payment-service
79-
dockerfile: Dockerfile
78+
context: .
79+
dockerfile: src/services/payment-service/Dockerfile
8080
ports:
8181
- "5003:8080"
8282
environment:
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# CHO Microservice Health Check Dependency Matrix
2+
3+
Each service exposes three standard health check endpoints via `CloudHealthOffice.Infrastructure`:
4+
5+
| Endpoint | Purpose | Behavior |
6+
|------------------|------------------|-----------------------------------------------|
7+
| `/health` | All checks | Runs every registered check |
8+
| `/health/live` | Liveness probe | Returns `Healthy` if the process is running |
9+
| `/health/ready` | Readiness probe | Checks all downstream dependencies |
10+
11+
## Dependency Checklist by Service
12+
13+
| Service | MongoDB | Cosmos DB | Redis | HTTP Dependencies | Notes |
14+
|----------------------------|---------|-----------|-------|--------------------------------|--------------------------------------|
15+
| claims-service | X | X | | | Uses shared infra (`AddChoInfrastructure`) |
16+
| benefit-plan-service | X | X | X | claims-service `/health/live` | Redis for accumulator cache |
17+
| payment-service | X | X | | claims-service `/health/live` | 835 ERA processing |
18+
| eligibility-service | X | X | | | 270/271 eligibility |
19+
| member-service | X | X | | | Member demographics |
20+
| provider-service | X | X | | | Provider directory |
21+
| enrollment-import-service | X | X | | | X12 834 import |
22+
| authorization-service | X | X | | | 278 prior auth |
23+
| coverage-service | X | X | | | Member-Sponsor-Plan linkage |
24+
| sponsor-service | X | X | | | Employer/group sponsors |
25+
| encounter-service | X | X | | | 837 encounter submission |
26+
| risk-adjustment-service | X | X | | | HCC risk scoring |
27+
| premium-billing-service | X | X | | | Premium invoicing |
28+
| smart-auth-service | X | | | | SMART on FHIR OIDC server (MongoDB only) |
29+
| fhir-service | X | | | | FHIR R4 API (MongoDB only) |
30+
| attachment-service | X | X | | | 275 clinical attachments |
31+
| appeals-service | X | X | | | Claim appeals |
32+
| rfai-service | X | X | | | Request for Additional Info |
33+
| reference-data-service | | | | | PostgreSQL (NpgSql health check) |
34+
| trading-partner-service | X | X | | | EDI trading partners |
35+
| tenant-service | X | X | | | SaaS tenant management |
36+
37+
> **Note:** Most services support both MongoDB and Cosmos DB. The health check auto-detects which database is configured — only the active datastore is checked at runtime.
38+
39+
## How Health Checks Are Configured
40+
41+
All services use `CloudHealthOffice.Infrastructure.HealthChecks.AddChoHealthChecks()`:
42+
43+
```csharp
44+
// Dual-database service (most services — auto-detects active datastore)
45+
builder.Services.AddChoHealthChecks(options =>
46+
{
47+
options.MongoDbConnectionString = builder.Configuration["MongoDb:ConnectionString"];
48+
options.CosmosDbConnectionString = builder.Configuration["CosmosDb:ConnectionString"];
49+
options.CosmosDbEndpoint = builder.Configuration["CosmosDb:Endpoint"];
50+
options.CosmosDbKey = builder.Configuration["CosmosDb:Key"];
51+
});
52+
53+
// Service with Redis + HTTP dependency (benefit-plan-service)
54+
builder.Services.AddChoHealthChecks(options =>
55+
{
56+
options.MongoDbConnectionString = builder.Configuration["MongoDb:ConnectionString"];
57+
options.CosmosDbConnectionString = builder.Configuration["CosmosDb:ConnectionString"];
58+
options.CosmosDbEndpoint = builder.Configuration["CosmosDb:Endpoint"];
59+
options.CosmosDbKey = builder.Configuration["CosmosDb:Key"];
60+
options.RedisConnectionString = builder.Configuration["Redis:ConnectionString"];
61+
options.HttpDependencies["claims-service"] = "http://claims-service:8080/health/live";
62+
});
63+
```
64+
65+
Health check endpoint mapping:
66+
```csharp
67+
app.MapChoHealthChecks(); // Maps /health, /health/live, /health/ready
68+
```
69+
70+
## Docker HEALTHCHECK
71+
72+
All Dockerfiles use the liveness probe:
73+
```dockerfile
74+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
75+
CMD curl -f http://localhost:8080/health/live || exit 1
76+
```
77+
78+
## Kubernetes Probe Configuration (Recommended)
79+
80+
```yaml
81+
livenessProbe:
82+
httpGet:
83+
path: /health/live
84+
port: 8080
85+
initialDelaySeconds: 10
86+
periodSeconds: 30
87+
readinessProbe:
88+
httpGet:
89+
path: /health/ready
90+
port: 8080
91+
initialDelaySeconds: 5
92+
periodSeconds: 10
93+
```
Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,37 @@
1-
# Build stage
21
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
3-
WORKDIR /src
2+
WORKDIR /repo
43

5-
# Copy csproj and restore dependencies
6-
COPY ["appeals-service.csproj", "./"]
7-
RUN dotnet restore "appeals-service.csproj"
4+
# Copy csproj files and restore (preserves layer caching)
5+
COPY src/services/appeals-service/appeals-service.csproj src/services/appeals-service/
6+
COPY src/services/shared/CloudHealthOffice.Infrastructure/CloudHealthOffice.Infrastructure.csproj src/services/shared/CloudHealthOffice.Infrastructure/
7+
RUN dotnet restore src/services/appeals-service/appeals-service.csproj
88

9-
# Copy everything else and build
10-
COPY . .
11-
RUN dotnet build "appeals-service.csproj" -c Release -o /app/build
9+
# Copy source code and build
10+
COPY src/services/appeals-service/ src/services/appeals-service/
11+
COPY src/services/shared/CloudHealthOffice.Infrastructure/ src/services/shared/CloudHealthOffice.Infrastructure/
12+
RUN dotnet build src/services/appeals-service/appeals-service.csproj -c Release --no-restore
1213

1314
# Publish stage
1415
FROM build AS publish
15-
RUN dotnet publish "appeals-service.csproj" -c Release -o /app/publish /p:UseAppHost=false
16+
RUN dotnet publish src/services/appeals-service/appeals-service.csproj -c Release -o /app/publish /p:UseAppHost=false --no-restore --no-build
1617

1718
# Runtime stage
18-
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
19+
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
1920
WORKDIR /app
2021

21-
# Create non-root user
22-
RUN groupadd -r appuser && useradd -r -g appuser appuser
22+
RUN apt-get update \
23+
&& apt-get install -y --no-install-recommends curl \
24+
&& rm -rf /var/lib/apt/lists/*
2325

24-
# Copy published files
2526
COPY --from=publish /app/publish .
2627

27-
# Set ownership
28-
RUN chown -R appuser:appuser /app
29-
30-
# Switch to non-root user
28+
RUN groupadd -r appuser && useradd -r -g appuser appuser \
29+
&& chown -R appuser:appuser /app
3130
USER appuser
3231

33-
# Expose port
3432
EXPOSE 8080
3533

36-
# Health check
3734
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
38-
CMD curl --fail http://localhost:8080/health || exit 1
39-
40-
# Set environment variables
41-
ENV ASPNETCORE_URLS=http://+:8080
42-
ENV ASPNETCORE_ENVIRONMENT=Production
35+
CMD curl -f http://localhost:8080/health/live || exit 1
4336

4437
ENTRYPOINT ["dotnet", "appeals-service.dll"]

src/services/appeals-service/Program.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.OpenApi.Models;
33
using AppealsService.Middleware;
44
using AppealsService.Repositories;
5+
using CloudHealthOffice.Infrastructure.HealthChecks;
56

67
var builder = WebApplication.CreateBuilder(args);
78

@@ -44,8 +45,14 @@
4445
// HTTP context accessor (for tenant middleware)
4546
builder.Services.AddHttpContextAccessor();
4647

47-
// Health checks
48-
builder.Services.AddHealthChecks();
48+
// Health checks (MongoDB or Cosmos DB)
49+
builder.Services.AddChoHealthChecks(options =>
50+
{
51+
options.MongoDbConnectionString = builder.Configuration["MongoDb:ConnectionString"];
52+
options.CosmosDbConnectionString = builder.Configuration["CosmosDb:ConnectionString"];
53+
options.CosmosDbEndpoint = builder.Configuration["CosmosDb:Endpoint"];
54+
options.CosmosDbKey = builder.Configuration["CosmosDb:Key"];
55+
});
4956

5057
// CORS (for development)
5158
builder.Services.AddCors(options =>
@@ -81,6 +88,6 @@
8188
app.UseAuthorization();
8289

8390
app.MapControllers();
84-
app.MapHealthChecks("/health");
91+
app.MapChoHealthChecks();
8592

8693
app.Run();

src/services/appeals-service/appeals-service.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</PropertyGroup>
1010

1111
<ItemGroup>
12+
<ProjectReference Include="..\shared\CloudHealthOffice.Infrastructure\CloudHealthOffice.Infrastructure.csproj" />
1213
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
1314
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.45.0" />
1415
<PackageReference Include="Azure.Storage.Blobs" Version="12.24.0" />
Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
# Build context must be the repo root so the CloudHealthOffice.DocumentStore
2-
# project reference (../../engines/...) is available during the build.
31
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
42
WORKDIR /repo
53

64
# Copy csproj files and restore (preserves layer caching)
75
COPY src/services/attachment-service/attachment-service.csproj src/services/attachment-service/
6+
COPY src/services/shared/CloudHealthOffice.Infrastructure/CloudHealthOffice.Infrastructure.csproj src/services/shared/CloudHealthOffice.Infrastructure/
87
COPY src/engines/CloudHealthOffice.DocumentStore/CloudHealthOffice.DocumentStore.csproj src/engines/CloudHealthOffice.DocumentStore/
98
RUN dotnet restore src/services/attachment-service/attachment-service.csproj
109

1110
# Copy source code and build
1211
COPY src/services/attachment-service/ src/services/attachment-service/
12+
COPY src/services/shared/CloudHealthOffice.Infrastructure/ src/services/shared/CloudHealthOffice.Infrastructure/
1313
COPY src/engines/CloudHealthOffice.DocumentStore/ src/engines/CloudHealthOffice.DocumentStore/
1414
RUN dotnet build src/services/attachment-service/attachment-service.csproj -c Release --no-restore
1515

@@ -18,16 +18,22 @@ FROM build AS publish
1818
RUN dotnet publish src/services/attachment-service/attachment-service.csproj -c Release -o /app/publish /p:UseAppHost=false --no-restore --no-build
1919

2020
# Runtime stage
21-
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
21+
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
2222
WORKDIR /app
23-
EXPOSE 8080
2423

25-
# Copy published app
24+
RUN apt-get update \
25+
&& apt-get install -y --no-install-recommends curl \
26+
&& rm -rf /var/lib/apt/lists/*
27+
2628
COPY --from=publish /app/publish .
2729

28-
# Create non-root user
2930
RUN groupadd -r appuser && useradd -r -g appuser appuser \
3031
&& chown -R appuser:appuser /app
3132
USER appuser
3233

34+
EXPOSE 8080
35+
36+
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
37+
CMD curl -f http://localhost:8080/health/live || exit 1
38+
3339
ENTRYPOINT ["dotnet", "attachment-service.dll"]

src/services/attachment-service/Program.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using AttachmentService.Repositories;
88
using AttachmentService.Services;
99
using CloudHealthOffice.DocumentStore;
10+
using CloudHealthOffice.Infrastructure.HealthChecks;
1011

1112
var builder = WebApplication.CreateBuilder(args);
1213

@@ -105,6 +106,15 @@
105106
builder.Services.AddSingleton<AcknowledgmentGeneratorService>();
106107
builder.Services.AddScoped<IAcknowledgmentService, AcknowledgmentService>();
107108

109+
// Health checks (MongoDB or Cosmos DB)
110+
builder.Services.AddChoHealthChecks(options =>
111+
{
112+
options.MongoDbConnectionString = builder.Configuration["MongoDb:ConnectionString"];
113+
options.CosmosDbConnectionString = builder.Configuration["CosmosDb:ConnectionString"];
114+
options.CosmosDbEndpoint = builder.Configuration["CosmosDb:Endpoint"];
115+
options.CosmosDbKey = builder.Configuration["CosmosDb:Key"];
116+
});
117+
108118
var app = builder.Build();
109119

110120
// Configure the HTTP request pipeline.
@@ -122,8 +132,7 @@
122132

123133
app.MapControllers();
124134

125-
// Health check endpoint (no auth required)
126-
app.MapGet("/health", () => Results.Ok(new { status = "healthy", service = "attachment-service" }))
127-
.AllowAnonymous();
135+
// Health check endpoints (no auth required — handled by middleware before routing)
136+
app.MapChoHealthChecks();
128137

129138
app.Run();

src/services/attachment-service/attachment-service.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10+
<ProjectReference Include="..\shared\CloudHealthOffice.Infrastructure\CloudHealthOffice.Infrastructure.csproj" />
1011
<ProjectReference Include="..\..\engines\CloudHealthOffice.DocumentStore\CloudHealthOffice.DocumentStore.csproj" />
1112
</ItemGroup>
1213
<ItemGroup>

0 commit comments

Comments
 (0)