我有以下端点:
[HttpPost("Submit")]
public String post()
{
_ = _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
Run Code Online (Sandbox Code Playgroud)
以及服务实现:
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return httpClient.PostAsync(<params>);
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行代码并调用端点时,不会触发 HTTP POST。但是,如果我将代码更改为:
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
Run Code Online (Sandbox Code Playgroud)
POST 按预期提交。为什么会发生这种情况?如果我并不真正关心 HTTP 响应,我该怎么办?我只想提交它并继续我的流程。我不应该能够在不await获取结果的情况下使用它吗?例如:
public void SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
httpClient.PostAsync(<params>);
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码有两个问题。如果其中一个被修复,就不会有问题:
PostAsync执行,退出using块,并且HttpClient在请求有机会启动之前实例就被处置。无论如何,创建 POST 不会花费很长时间,因此无需使该方法“即发即忘”。此外,很少有应用程序可以接受丢失指标,尤其是当出现问题时。这就是指标最有用的时候。这就是为什么 ASP.NET Core 6 添加了对 OpenTelemetry 跟踪和指标的内置支持。最后将详细介绍这一点,但支持包也可以在 ASP.NET Framework 中使用。您也许可以用内置服务替换当前的服务。
使用await - 还不够
解决此问题的一种方法是使用await,但这并不能解决 HttpClient 使用问题。
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
Run Code Online (Sandbox Code Playgroud)
至少 HttpClient 应该存储在一个字段中。一旦完成,就不再有任何理由await,只要服务本身仍然存在:
HttpClient httpClient = new HttpClient();
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
return httpClient.PostAsync(<params>);
}
Run Code Online (Sandbox Code Playgroud)
长期服务
这使我们能够保持服务。在 ASP.NET 和 ASP.NET Core 中,每个请求都由 Controller 类的新实例中的单独线程提供服务。请求本身用作 GC 范围,因此请求期间创建的任何内容都会在请求结束后被处理,包括 HttpClient 实例。
为了保留 Metrics 服务,我们需要将其注册为SingletonASP.NET Core 的 DI,将其设为后台服务,或者确保它是 ASP.NET Framework 中的单例。我们可以使该字段静态,但这会导致下一个问题。
正确的 HttpClient 使用
如果用作单例,HttpClient 仍然会导致问题。HttpClient 将套接字缓存到特定的机器。如果该机器消失,HttpClient 仍会尝试与其通信,从而导致错误。当远程服务使用负载平衡器或故障转移到新服务器时,很容易发生这种情况。为了解决这个问题,HttpClient 实例或者更确切地说是套接字需要定期回收。
这就是 HttpClientFactory 的工作。此类缓存并回收 SocketClientHandler 实例,这些类在 HttpClient 中执行实际工作。这些会定期回收,例如每 10 分钟回收一次。当请求新的 HttpClient 实例时,它会创建一个包装已有可用处理程序之一的新实例。
当您services.AddHttpClient在 ASP.NET Core 中使用时,您实际上是在配置 HttpClientFactory。当您在控制器中添加 HttpClient 依赖项时,该实例将由配置的 HttpClientFactory 创建。
这意味着以下操作可以正常工作:
HttpClient _client;
public MyController(HttpClient client)
{
_client=client;
}
[HttpPost("Submit")]
public String post()
{
await _client.PostAsync(<params>);
return "done";
}
Run Code Online (Sandbox Code Playgroud)
具有依赖关系的作用域服务HttpClient也可以工作:
MyService _service;
public MyController(MyService service)
{
_service=service;
}
HttpPost("Submit")]
public String post()
{
await _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
Run Code Online (Sandbox Code Playgroud)
哪里MyService:
class MyService
{
HttpClient _client;
public MyService(HttpClient client)
{
_client=client;
}
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
return httpClient.PostAsync(<params>);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,没有真正需要在内部等待SubmitMetric,这由操作来处理。
使用内置的 OpenTelemetry 跟踪和指标
即将推出的长期支持版本 ASP.NET Core 6 添加了对 OpenTelemetry 标准的本机支持,用于日志记录、跟踪和指标。这允许使用标准 API 将指标推送到许多不同的可观察性应用程序,例如 Prometheus、Jaeger、Zipking、Elastic 和 Splunk。
与其滚动自己的指标基础设施,不如使用标准 API。OpenTelemetry for .NET在 ASP.NET Framework 4.6 及更高版本中支持此功能。ASP.NET Core 5 及更高版本可通过内置命名空间和类向 OpenTelemetry 提供程序发布指标和跟踪。System.DiagnosticsActivity
事实上,控制器已经进行了检测,因此您可以摆脱指标服务,将任何标签和行李添加到请求的当前活动中:
[HttpPost("Submit")]
public String post()
{
Activity.Current?.AddTag("test");
...
return "done";
}
Run Code Online (Sandbox Code Playgroud)
ASP.NET Core 6 Preview 5 中添加了指标:
Meter meter = new Meter("my.library.meter.name", "v1.0");
Counter<int> _counter;
public MyController(...)
{
_counter = meter.CreateCounter<int>("Requests");
}
[HttpPost("Submit")]
public String post()
{
counter.Add(60, KeyValuePair.Create<string, object>("request", "test"));
return "done";
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2632 次 |
| 最近记录: |