-
Notifications
You must be signed in to change notification settings - Fork 926
Adapt OpenAI health check based on endpoint configuration #11763
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
dd4a89f
b5f8fda
4cae8ed
1399972
54f5e80
b00e489
4d2152b
df2df9b
b61040e
8050e74
c8a3897
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,49 +3,66 @@ | |
|
|
||
| using System.Text.Json; | ||
| using Microsoft.Extensions.Diagnostics.HealthChecks; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Aspire.Hosting.OpenAI; | ||
|
|
||
| /// <summary> | ||
| /// Checks a StatusPage "status.json" endpoint and maps indicator to ASP.NET Core health status. | ||
| /// Health check for OpenAI resources that adapts based on endpoint configuration. | ||
| /// </summary> | ||
| internal sealed class StatusPageHealthCheck : IHealthCheck | ||
| internal sealed class OpenAIHealthCheck : IHealthCheck | ||
| { | ||
| private const string DefaultEndpoint = "https://api.openai.com/v1"; | ||
| private readonly IHttpClientFactory _httpClientFactory; | ||
| private readonly Uri _statusEndpoint; | ||
| private readonly OpenAIResource _resource; | ||
| private readonly string? _httpClientName; | ||
| private readonly TimeSpan _timeout; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="StatusPageHealthCheck"/> class. | ||
| /// Initializes a new instance of the <see cref="OpenAIHealthCheck"/> class. | ||
| /// </summary> | ||
| /// <param name="httpClientFactory">The factory to create HTTP clients.</param> | ||
| /// <param name="statusEndpoint">The URI of the status.json endpoint.</param> | ||
| /// <param name="resource">The OpenAI resource.</param> | ||
| /// <param name="httpClientName">The optional name of the HTTP client to use.</param> | ||
| /// <param name="timeout">The optional timeout for the HTTP request.</param> | ||
| public StatusPageHealthCheck( | ||
| public OpenAIHealthCheck( | ||
| IHttpClientFactory httpClientFactory, | ||
| Uri statusEndpoint, | ||
| OpenAIResource resource, | ||
| string? httpClientName = null, | ||
| TimeSpan? timeout = null) | ||
| { | ||
| _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory)); | ||
| _statusEndpoint = statusEndpoint ?? throw new ArgumentNullException(nameof(statusEndpoint)); | ||
| _resource = resource ?? throw new ArgumentNullException(nameof(resource)); | ||
| _httpClientName = httpClientName; | ||
| _timeout = timeout ?? TimeSpan.FromSeconds(5); | ||
| } | ||
|
|
||
| public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) | ||
| { | ||
| // Case 1: Default endpoint - check StatusPage | ||
| if (_resource.Endpoint == DefaultEndpoint) | ||
| { | ||
| return await CheckStatusPageAsync(cancellationToken).ConfigureAwait(false); | ||
| } | ||
|
|
||
| // Case 2: Custom endpoint - return healthy | ||
| return await CheckEndpointHealthAsync().ConfigureAwait(false); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Checks the StatusPage endpoint for the default OpenAI service. | ||
| /// </summary> | ||
| private async Task<HealthCheckResult> CheckStatusPageAsync(CancellationToken cancellationToken) | ||
| { | ||
| var client = string.IsNullOrWhiteSpace(_httpClientName) | ||
| ? _httpClientFactory.CreateClient() | ||
| : _httpClientFactory.CreateClient(_httpClientName); | ||
|
|
||
| var statusEndpoint = new Uri("https://status.openai.com/api/v2/status.json"); | ||
|
|
||
| using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); | ||
| cts.CancelAfter(_timeout); | ||
|
|
||
| using var req = new HttpRequestMessage(HttpMethod.Get, _statusEndpoint); | ||
| using var req = new HttpRequestMessage(HttpMethod.Get, statusEndpoint); | ||
| req.Headers.Accept.ParseAdd("application/json"); | ||
|
|
||
| HttpResponseMessage resp; | ||
|
|
@@ -94,7 +111,7 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context | |
| { | ||
| ["indicator"] = indicator, | ||
| ["description"] = description, | ||
| ["endpoint"] = _statusEndpoint.ToString() | ||
| ["endpoint"] = statusEndpoint.ToString() | ||
| }; | ||
|
|
||
| // Map indicator -> HealthStatus | ||
|
|
@@ -112,39 +129,12 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context | |
| return HealthCheckResult.Unhealthy("Failed to parse StatusPage JSON.", jex); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| internal static class StatuspageHealthCheckExtensions | ||
| { | ||
| /// <summary> | ||
| /// Registers a StatusPage health check for a given status.json URL. | ||
| /// Returns healthy for custom endpoints. | ||
| /// </summary> | ||
| public static IDistributedApplicationBuilder AddStatusPageCheck( | ||
| this IDistributedApplicationBuilder builder, | ||
| string name, | ||
| string statusJsonUrl, | ||
| string? httpClientName = null, | ||
| TimeSpan? timeout = null, | ||
| HealthStatus? failureStatus = null, | ||
| IEnumerable<string>? tags = null) | ||
| private static Task<HealthCheckResult> CheckEndpointHealthAsync() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the point of this method?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot just inline this code.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inlined the method - now directly returns Commit: c8a3897 |
||
| { | ||
| ArgumentNullException.ThrowIfNull(builder); | ||
| ArgumentException.ThrowIfNullOrWhiteSpace(name); | ||
| ArgumentException.ThrowIfNullOrWhiteSpace(statusJsonUrl); | ||
|
|
||
| // Ensure IHttpClientFactory is available by registering HTTP client services | ||
| builder.Services.AddHttpClient(); | ||
|
|
||
| builder.Services.AddHealthChecks().Add(new HealthCheckRegistration( | ||
| name: name, | ||
| factory: sp => | ||
| { | ||
| var httpFactory = sp.GetRequiredService<IHttpClientFactory>(); | ||
| return new StatusPageHealthCheck(httpFactory, new Uri(statusJsonUrl), httpClientName, timeout); | ||
| }, | ||
| failureStatus: failureStatus, | ||
| tags: tags)); | ||
|
|
||
| return builder; | ||
| return Task.FromResult(HealthCheckResult.Healthy("Custom OpenAI endpoint configured")); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.