33
44using System . Text . Json ;
55using Microsoft . Extensions . Diagnostics . HealthChecks ;
6- using Microsoft . Extensions . DependencyInjection ;
76
87namespace Aspire . Hosting . OpenAI ;
98
109/// <summary>
11- /// Checks a StatusPage "status.json" endpoint and maps indicator to ASP.NET Core health status .
10+ /// Health check for OpenAI resources that adapts based on endpoint configuration .
1211/// </summary>
13- internal sealed class StatusPageHealthCheck : IHealthCheck
12+ internal sealed class OpenAIHealthCheck : IHealthCheck
1413{
14+ private static readonly Uri s_defaultEndpointUri = new ( "https://api.openai.com/v1" ) ;
15+ private static readonly Uri s_statusPageUri = new ( "https://status.openai.com/api/v2/status.json" ) ;
16+
1517 private readonly IHttpClientFactory _httpClientFactory ;
16- private readonly Uri _statusEndpoint ;
18+ private readonly OpenAIResource _resource ;
1719 private readonly string ? _httpClientName ;
1820 private readonly TimeSpan _timeout ;
1921
2022 /// <summary>
21- /// Initializes a new instance of the <see cref="StatusPageHealthCheck "/> class.
23+ /// Initializes a new instance of the <see cref="OpenAIHealthCheck "/> class.
2224 /// </summary>
2325 /// <param name="httpClientFactory">The factory to create HTTP clients.</param>
24- /// <param name="statusEndpoint ">The URI of the status.json endpoint .</param>
26+ /// <param name="resource ">The OpenAI resource .</param>
2527 /// <param name="httpClientName">The optional name of the HTTP client to use.</param>
2628 /// <param name="timeout">The optional timeout for the HTTP request.</param>
27- public StatusPageHealthCheck (
29+ public OpenAIHealthCheck (
2830 IHttpClientFactory httpClientFactory ,
29- Uri statusEndpoint ,
31+ OpenAIResource resource ,
3032 string ? httpClientName = null ,
3133 TimeSpan ? timeout = null )
3234 {
3335 _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException ( nameof ( httpClientFactory ) ) ;
34- _statusEndpoint = statusEndpoint ?? throw new ArgumentNullException ( nameof ( statusEndpoint ) ) ;
36+ _resource = resource ?? throw new ArgumentNullException ( nameof ( resource ) ) ;
3537 _httpClientName = httpClientName ;
3638 _timeout = timeout ?? TimeSpan . FromSeconds ( 5 ) ;
3739 }
3840
3941 public async Task < HealthCheckResult > CheckHealthAsync ( HealthCheckContext context , CancellationToken cancellationToken = default )
42+ {
43+ // Case 1: Default endpoint - check StatusPage
44+ if ( Uri . TryCreate ( _resource . Endpoint , UriKind . Absolute , out var endpointUri ) &&
45+ Uri . Compare ( endpointUri , s_defaultEndpointUri , UriComponents . SchemeAndServer , UriFormat . Unescaped , StringComparison . OrdinalIgnoreCase ) == 0 )
46+ {
47+ return await CheckStatusPageAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
48+ }
49+
50+ // Case 2: Custom endpoint - return healthy
51+ return HealthCheckResult . Healthy ( "Custom OpenAI endpoint configured" ) ;
52+ }
53+
54+ /// <summary>
55+ /// Checks the StatusPage endpoint for the default OpenAI service.
56+ /// </summary>
57+ private async Task < HealthCheckResult > CheckStatusPageAsync ( CancellationToken cancellationToken )
4058 {
4159 var client = string . IsNullOrWhiteSpace ( _httpClientName )
4260 ? _httpClientFactory . CreateClient ( )
@@ -45,7 +63,7 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
4563 using var cts = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken ) ;
4664 cts . CancelAfter ( _timeout ) ;
4765
48- using var req = new HttpRequestMessage ( HttpMethod . Get , _statusEndpoint ) ;
66+ using var req = new HttpRequestMessage ( HttpMethod . Get , s_statusPageUri ) ;
4967 req . Headers . Accept . ParseAdd ( "application/json" ) ;
5068
5169 HttpResponseMessage resp ;
@@ -94,7 +112,7 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
94112 {
95113 [ "indicator" ] = indicator ,
96114 [ "description" ] = description ,
97- [ "endpoint" ] = _statusEndpoint . ToString ( )
115+ [ "endpoint" ] = s_statusPageUri . ToString ( )
98116 } ;
99117
100118 // Map indicator -> HealthStatus
@@ -113,38 +131,3 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
113131 }
114132 }
115133}
116-
117- internal static class StatuspageHealthCheckExtensions
118- {
119- /// <summary>
120- /// Registers a StatusPage health check for a given status.json URL.
121- /// </summary>
122- public static IDistributedApplicationBuilder AddStatusPageCheck (
123- this IDistributedApplicationBuilder builder ,
124- string name ,
125- string statusJsonUrl ,
126- string ? httpClientName = null ,
127- TimeSpan ? timeout = null ,
128- HealthStatus ? failureStatus = null ,
129- IEnumerable < string > ? tags = null )
130- {
131- ArgumentNullException . ThrowIfNull ( builder ) ;
132- ArgumentException . ThrowIfNullOrWhiteSpace ( name ) ;
133- ArgumentException . ThrowIfNullOrWhiteSpace ( statusJsonUrl ) ;
134-
135- // Ensure IHttpClientFactory is available by registering HTTP client services
136- builder . Services . AddHttpClient ( ) ;
137-
138- builder . Services . AddHealthChecks ( ) . Add ( new HealthCheckRegistration (
139- name : name ,
140- factory : sp =>
141- {
142- var httpFactory = sp . GetRequiredService < IHttpClientFactory > ( ) ;
143- return new StatusPageHealthCheck ( httpFactory , new Uri ( statusJsonUrl ) , httpClientName , timeout ) ;
144- } ,
145- failureStatus : failureStatus ,
146- tags : tags ) ) ;
147-
148- return builder ;
149- }
150- }
0 commit comments