Azure函数中的AspNetCore.HealthCheck在不健康的情况下始终返回200。

huangapple go评论66阅读模式
英文:

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

问题

我们有一个使用.Net Core 7的Azure函数,我们已经添加了一个HealthCheck。如果状态设置为不健康,健康检查会触发,我们返回一个 ServiceUnavailableObjectResult 的实例。无论我们返回什么,HTTP状态码始终返回200。

来自 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");

来自 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));
}

期望的结果:

  • 返回的HTTP状态码为503 - 服务不可用,以及有效负载。

实际结果:

  • 返回的HTTP状态码是200 - 正常,以及有效负载。
  • 在Web API项目中用于HealthChecks的相同代码按预期返回503。

Azure函数中的AspNetCore.HealthCheck在不健康的情况下始终返回200。

任何建议将不胜感激。

英文:

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($&quot;{baseAddress}/health&quot;),
        name: &quot;Mgmt&quot;)
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.IncomingContainerName),
        name: &quot;IncomingBlobContainer&quot;)
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.ErrorContainerName),
        name: &quot;ErrorBlobContainer&quot;)
    .AddAzureBlobStorage(
        connectionString: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.BlobConnectionStringName),
        containerName: context.Configuration.GetValue&lt;string&gt;(RecipientUploadOptions.ArchiveContainerName),
        name: &quot;ArchiveBlobContainer&quot;);

From HealthCheckFunction.cs

[Function(&quot;health&quot;)]
public async Task&lt;IActionResult&gt; Health([HttpTrigger(AuthorizationLevel.Anonymous, &quot;get&quot;, &quot;post&quot;)] 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

Azure函数中的AspNetCore.HealthCheck在不健康的情况下始终返回200。

Any suggestions would be greatly appreaciated

答案1

得分: 1

有两种方式可以在使用.NET Isolated Worker时开发HTTP函数。

内置HTTP模型

对于这种方式,您需要返回如下的HttpResponseData类型:

[Function(nameof(Health))]
public async Task&lt;HttpResponseData&gt; Health([HttpTrigger(AuthorizationLevel.Function, &quot;get&quot;, &quot;post&quot;)] 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集成(预览版)

要使这个模型工作,需要满足一些先决条件,这些条件在上面链接的文档中有详细说明。以下是供参考的同样要求:

  1. 安装 Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore NuGet 包,版本为 1.0.0-preview2 或更高(请注意,您必须在 Visual Studio 中勾选“包括预发行版本”复选框)

    此外,请确保 Microsoft.Azure.Functions.Worker.Sdk 版本为 1.11.0 或更高,以及 Microsoft.Azure.Functions.Worker 版本为 1.16.0 或更高。

  2. Program.cs 中将 ConfigureFunctionsWorkerDefaults 替换为 ConfigureFunctionsWebApplication

  3. 使用 ASP.NET 中的 HttpRequestIActionResult 类型

  4. 添加名为 AzureWebJobsFeatureFlags 的应用设置,值为 EnableHttpProxying

英文:

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&lt;HttpResponseData&gt; Health([HttpTrigger(AuthorizationLevel.Function, &quot;get&quot;, &quot;post&quot;)] 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

答案2

得分: 0

以下是基于Pramod的答案实现的代码部分的翻译:

[Function(nameof(Health))]
public async Task<HttpResponseData> Health([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
{
    //HACK (解决方法)
    //由于Azure Function框架在健康检查中的行为
    //无论状态如何都会返回200,忽略了
    //IActionResult。暂时的解决方案是更接近底层
    //并编写我们自己的响应主体。ASP.NET Core集成(用于Azure
    //Functions)仍处于预览阶段(现在还不能很好地解决问题
    //但可能在未来更好地解决这个问题)。

    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[] { },
        // Entries = status.Entries,
        // ^^^^ 这会很好,但不能直接序列化并且会
        // 抛出NotSupportedException。这可能很有用
        // 因为它提供了有关什么不健康的详细信息
        ContentType = "application/json",
        StatusCode = httpStatus
    };

    await response.WriteAsJsonAsync(statusResult, httpStatus);

    return response;
}
英文:

Here is implementation based on Pramod's answer here.

[Function(nameof(Health))]
public async Task&lt;HttpResponseData&gt; Health([HttpTrigger(AuthorizationLevel.Function, &quot;get&quot;, &quot;post&quot;)] HttpRequestData req)
{
    //HACK (Work around)
    //Due to a behavior in the Azure Function framework for health checks
    //will always return a 200 regardless of state and ignore the
    //IActionResult. The solution--for now--is to get closer to the metal
    //and write our own response body. ASP.NET Core integration (for Azure
    //Functions) is still in preview (and not solving the problem for us
    //right this moment but may hold the key for doing this better in the
    //future.

    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[] { },
        // Entries = status.Entries,
        // ^^^^ This would be nice but doesn&#39;t directly serialize and will
        // throw a NotSupportedException. That may be useful to explore
        // since it gives details about what is unhealthy
        ContentType = &quot;application/json&quot;,
        StatusCode = httpStatus
    };

    await response.WriteAsJsonAsync(statusResult, httpStatus);

    return response;
}

huangapple
  • 本文由 发表于 2023年7月12日 21:45:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76671276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定