Share via

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

Miss Amber in Seattle 21 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.

Developer technologies | ASP.NET Core | Other

Answer accepted by question author

Pramod Valavala 20,661 Reputation points Microsoft Employee Moderator
2023-07-12T19:47:17.29+00:00

@Miss Amber in Seattle 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

Was this answer helpful?

1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Miss Amber in Seattle 21 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;
        }
    

    Was this answer helpful?

    0 comments No comments

Your answer

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