1010using System . Threading . Tasks ;
1111using Azure . DataApiBuilder . Config . HealthCheck ;
1212using Azure . DataApiBuilder . Config . ObjectModel ;
13+ using Azure . DataApiBuilder . Config . ObjectModel . Embeddings ;
1314using Azure . DataApiBuilder . Core . Authorization ;
15+ using Azure . DataApiBuilder . Core . Services . Embeddings ;
1416using Azure . DataApiBuilder . Product ;
1517using Microsoft . AspNetCore . Http ;
1618using Microsoft . Extensions . Logging ;
@@ -27,20 +29,24 @@ public class HealthCheckHelper
2729 // Dependencies
2830 private ILogger < HealthCheckHelper > _logger ;
2931 private HttpUtilities _httpUtility ;
32+ private IEmbeddingService ? _embeddingService ;
3033 private string _incomingRoleHeader = string . Empty ;
3134 private string _incomingRoleToken = string . Empty ;
3235
3336 private const string TIME_EXCEEDED_ERROR_MESSAGE = "The threshold for executing the request has exceeded." ;
37+ private const string DIMENSIONS_MISMATCH_ERROR_MESSAGE = "The embedding dimensions do not match the expected dimensions." ;
3438
3539 /// <summary>
3640 /// Constructor to inject the logger and HttpUtility class.
3741 /// </summary>
3842 /// <param name="logger">Logger to track the log statements.</param>
3943 /// <param name="httpUtility">HttpUtility to call methods from the internal class.</param>
40- public HealthCheckHelper ( ILogger < HealthCheckHelper > logger , HttpUtilities httpUtility )
44+ /// <param name="embeddingService">Optional embedding service for embedding health checks.</param>
45+ public HealthCheckHelper ( ILogger < HealthCheckHelper > logger , HttpUtilities httpUtility , IEmbeddingService ? embeddingService = null )
4146 {
4247 _logger = logger ;
4348 _httpUtility = httpUtility ;
49+ _embeddingService = embeddingService ;
4450 }
4551
4652 /// <summary>
@@ -159,6 +165,7 @@ private async Task UpdateHealthCheckDetailsAsync(ComprehensiveHealthCheckReport
159165 comprehensiveHealthCheckReport . Checks = new List < HealthCheckResultEntry > ( ) ;
160166 await UpdateDataSourceHealthCheckResultsAsync ( comprehensiveHealthCheckReport , runtimeConfig ) ;
161167 await UpdateEntityHealthCheckResultsAsync ( comprehensiveHealthCheckReport , runtimeConfig ) ;
168+ await UpdateEmbeddingsHealthCheckResultsAsync ( comprehensiveHealthCheckReport , runtimeConfig ) ;
162169 }
163170
164171 // Updates the DataSource Health Check Results in the response.
@@ -351,5 +358,108 @@ private async Task PopulateEntityHealthAsync(ComprehensiveHealthCheckReport comp
351358
352359 return ( HealthCheckConstants . ERROR_RESPONSE_TIME_MS , errorMessage ) ;
353360 }
361+
362+ /// <summary>
363+ /// Updates the Embeddings Health Check Results in the response.
364+ /// Executes a test embedding and validates response time and optionally dimensions.
365+ /// </summary>
366+ private async Task UpdateEmbeddingsHealthCheckResultsAsync ( ComprehensiveHealthCheckReport comprehensiveHealthCheckReport , RuntimeConfig runtimeConfig )
367+ {
368+ EmbeddingsOptions ? embeddingsOptions = runtimeConfig ? . Runtime ? . Embeddings ;
369+ EmbeddingsHealthCheckConfig ? healthConfig = embeddingsOptions ? . Health ;
370+
371+ // Only run health check if embeddings is enabled, health check is enabled, and embedding service is available
372+ if ( embeddingsOptions is null || ! embeddingsOptions . Enabled || healthConfig is null || ! healthConfig . Enabled || _embeddingService is null )
373+ {
374+ return ;
375+ }
376+
377+ if ( comprehensiveHealthCheckReport . Checks is null )
378+ {
379+ comprehensiveHealthCheckReport . Checks = new List < HealthCheckResultEntry > ( ) ;
380+ }
381+
382+ string testText = healthConfig . TestText ;
383+ int thresholdMs = healthConfig . ThresholdMs ;
384+ int ? expectedDimensions = healthConfig . ExpectedDimensions ;
385+
386+ try
387+ {
388+ Stopwatch stopwatch = new ( ) ;
389+ stopwatch . Start ( ) ;
390+ EmbeddingResult result = await _embeddingService . TryEmbedAsync ( testText ) ;
391+ stopwatch . Stop ( ) ;
392+
393+ int responseTimeMs = ( int ) stopwatch . ElapsedMilliseconds ;
394+ bool isResponseTimeWithinThreshold = responseTimeMs <= thresholdMs ;
395+ bool isDimensionsValid = true ;
396+ string ? errorMessage = null ;
397+
398+ if ( ! result . Success )
399+ {
400+ errorMessage = result . ErrorMessage ?? "Embedding request failed." ;
401+ comprehensiveHealthCheckReport . Checks . Add ( new HealthCheckResultEntry
402+ {
403+ Name = "embeddings" ,
404+ ResponseTimeData = new ResponseTimeData
405+ {
406+ ResponseTimeMs = HealthCheckConstants . ERROR_RESPONSE_TIME_MS ,
407+ ThresholdMs = thresholdMs
408+ } ,
409+ Exception = errorMessage ,
410+ Tags = new List < string > { HealthCheckConstants . EMBEDDING } ,
411+ Status = HealthStatus . Unhealthy
412+ } ) ;
413+ return ;
414+ }
415+
416+ // Validate dimensions if expected dimensions is specified
417+ if ( expectedDimensions . HasValue && result . Embedding is not null )
418+ {
419+ isDimensionsValid = result . Embedding . Length == expectedDimensions . Value ;
420+ if ( ! isDimensionsValid )
421+ {
422+ errorMessage = $ "{ DIMENSIONS_MISMATCH_ERROR_MESSAGE } Expected: { expectedDimensions . Value } , Actual: { result . Embedding . Length } ";
423+ }
424+ }
425+
426+ // Check response time threshold
427+ if ( ! isResponseTimeWithinThreshold )
428+ {
429+ errorMessage = errorMessage is null ? TIME_EXCEEDED_ERROR_MESSAGE : $ "{ errorMessage } { TIME_EXCEEDED_ERROR_MESSAGE } ";
430+ }
431+
432+ bool isHealthy = isResponseTimeWithinThreshold && isDimensionsValid ;
433+
434+ comprehensiveHealthCheckReport . Checks . Add ( new HealthCheckResultEntry
435+ {
436+ Name = "embeddings" ,
437+ ResponseTimeData = new ResponseTimeData
438+ {
439+ ResponseTimeMs = responseTimeMs ,
440+ ThresholdMs = thresholdMs
441+ } ,
442+ Exception = errorMessage ,
443+ Tags = new List < string > { HealthCheckConstants . EMBEDDING } ,
444+ Status = isHealthy ? HealthStatus . Healthy : HealthStatus . Unhealthy
445+ } ) ;
446+ }
447+ catch ( Exception ex )
448+ {
449+ _logger . LogError ( ex , "Error executing embeddings health check." ) ;
450+ comprehensiveHealthCheckReport . Checks . Add ( new HealthCheckResultEntry
451+ {
452+ Name = "embeddings" ,
453+ ResponseTimeData = new ResponseTimeData
454+ {
455+ ResponseTimeMs = HealthCheckConstants . ERROR_RESPONSE_TIME_MS ,
456+ ThresholdMs = thresholdMs
457+ } ,
458+ Exception = ex . Message ,
459+ Tags = new List < string > { HealthCheckConstants . EMBEDDING } ,
460+ Status = HealthStatus . Unhealthy
461+ } ) ;
462+ }
463+ }
354464 }
355465}
0 commit comments