Search code examples
asp.net-core.net-coreazure-functionshealth-check

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


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

Screen capture of a Google Chrome browser instance and nertwork showing the HTTP ststus of 200 and the JSON body indicating a 503 error result

Any suggestions would be greatly appreaciated


Solution

  • 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.

    2. Replace ConfigureFunctionsWorkerDefaults with ConfigureFunctionsWebApplication in Program.cs

    3. Use HttpRequest and IActionResult types from ASP.NET

    4. Add the AzureWebJobsFeatureFlags app setting with value EnableHttpProxying