AspNetCore.HealthCheck in Azure function always returns 200 even when unhealthy

Amber Clark 20 Reputation points
2023-07-12T14:11:42.9+00:00

We have an Azure Function using .Net Core 7 that we've added a HealthCheck to. The healthcheck fires, if the status is set to unhealthy, we return a an instance of ServiceUnavailableObjectResult. The HTTP status code always returns 200 regardless of what we return.

From Program.cs

services.AddHealthChecks()
    .AddUrlGroup(
        uri: new Uri($"{baseAddress}/health"),
        name: "Mgmt")
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue<string>(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue<string>(RecipientUploadOptions.IncomingContainerName),
        name: "IncomingBlobContainer")
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue<string>(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue<string>(RecipientUploadOptions.ErrorContainerName),
        name: "ErrorBlobContainer")
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue<string>(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue<string>(RecipientUploadOptions.ArchiveContainerName),
        name: "ArchiveBlobContainer");

From HealthCheckFunction.cs

Function("health")]
public async Task<IActionResult> Health([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData z)
{
    var status = await _healthCheckService.CheckHealthAsync();
    if (status.Status == HealthStatus.Healthy)
    {
        return new OkObjectResult(Enum.GetName(typeof(HealthStatus), status.Status));
    }

    return new ServiceUnavailableObjectResult(Enum.GetName(typeof(HealthStatus), status.Status));
}

Expected:

  • The HTTP status code returned is 503 - Service Unavailable along with the payload.

Actual:

  • The HTTP status code returned os 200 - OK along with the payload
  • The same code used for HealthChecks in web API projects return 503 as expected

ScreenCap

Any suggestions would be greatly appreciated.

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,911 questions
Developer technologies ASP.NET ASP.NET Core
{count} votes

Accepted answer
  1. Pramod Valavala 20,656 Reputation points Microsoft Employee Moderator
    2023-07-12T19:47:17.29+00:00

    @Amber Clark There are two ways you can develop HTTP functions when using .NET Isloted Worker.

    Built-in HTTP Model

    For this you need to return the HttpResponseData type as follows

    [Function(nameof(Health))]
    public async Task<HttpResponseData> Health([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
    {
        var response = req.CreateResponse();
    
        var status = await _healthCheckService.CheckHealthAsync();
    
        await response.WriteAsJsonAsync(
            Enum.GetName(typeof(HealthStatus), status.Status),
            status.Status == HealthStatus.Healthy ? HttpStatusCode.OK : HttpStatusCode.ServiceUnavailable
        );
    
        return response;
    }
    

    ASP.NET Core integration (preview)

    There are a few pre-requisites to get this model to work which are documented in the doc linked above. Here are the same for reference.

    1. Install the Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore NuGet package, version 1.0.0-preview2 or later (Note that you must check the include prerelease checkbox in Visual Studio)

    Also, make sure Microsoft.Azure.Functions.Worker.Sdk is version 1.11.0 or later and Microsoft.Azure.Functions.Worker is version 1.16.0 or later.

    1. Replace ConfigureFunctionsWorkerDefaults with ConfigureFunctionsWebApplication in Program.cs
    2. Use HttpRequest and IActionResult types from ASP.NET
    3. Add the AzureWebJobsFeatureFlags app setting with value EnableHttpProxying
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Amber Clark 20 Reputation points
    2023-07-14T15:39:49.5+00:00

    Based on @Pramod Valavala 's code above, here is my implementation.

     [Function(nameof(Health))]
        public async Task<HttpResponseData> Health([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
        {
            var response = req.CreateResponse();
            var status = await _healthCheckService.CheckHealthAsync();
    
            var httpStatus = (status.Status == HealthStatus.Healthy
                ? HttpStatusCode.OK
                : HttpStatusCode.ServiceUnavailable);
    
            var statusResult = new
            {
                Value = Enum.GetName(typeof(HealthStatus), status.Status),
                Formatters = new string[] { },
                ContentType = "application/json",
                StatusCode = httpStatus
            };
    
            await response.WriteAsJsonAsync(statusResult, httpStatus);
    
            return response;
        }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.