如果不等待请求,HttpClient 的生存时间是多少?

问题描述 投票:0回答:1

我有一个 C# .Net 8 Minimal API 应用程序,其中有一项服务使用 HTTPClient 与不同的 API 进行通信。关键是对我的应用程序的一个请求会触发对不同 API 的数千个请求,并且与不同 API 的通信可能需要几个小时。

设置如下:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IService, MyService>();
builder.Services.AddHttpClient<IApi, Api>();

var app = builder.Build();
app.UseRouting();

app.MapPost("/start", Func)

app.Run();

static async Task<IResult> Func(List<Object> os, IService service, IApi api)
{    
    service.SetApi(api);
 
    // What happens if the await is removed? Request is done and service and api will be cleaned up, or?
    await service.StartLongJobWithDifferentAPI(os);

    return Results.Ok();
}

public async Task<List<string>> StartLongJobWithDifferentAPI(List<Object> os)
{
    var tasks = new List<Task<string>>();
    foreach (var o in os)
    {
        tasks.Add(((Func<Task<string>>)(async (o) =>{
          var response = await _apiclient.PostAsJsonAsync("/post", o);
          return await response.Content.ReadAsStringAsync();})));
    }
    return (await Task.WhenAll(tasks)).ToList();
}

所以我的问题是: 如果删除等待,请求将以 Results.Ok() 结束,服务和 HTTPClient api 被清理,正在运行的任务将被中止,或者?

但是任务仍在运行,因此垃圾收集器不会清理任何东西,或者?

对我来说,不等待似乎是非常糟糕的做法,因为你失去了对错误管理(异常,404,...)的控制,并且你可能最终会在不受控制的情况下运行大量僵尸任务。 或者有人对长时间运行的任务使用这种不等待模式吗?

另一方面,“/start”端点的职责只是启动进程,我们对响应不感兴趣。

c# async-await dotnet-httpclient minimal-apis
1个回答
0
投票

首先 - 避免使用“即发即弃”任务,最好至少使用类似 ASP.NET Core 中托管服务的后台任务,这将允许您管理并发并监控任务的完成情况。

如果去掉await会发生什么?请求完成,服务和 api 将被清理,或者?

这取决于细节。据我所知,默认情况下,注入的

HttpClient
不会在作用域(在 ASP.NET Core 处理程序/操作的情况下为 == 请求)时被处理,但是如果您在
IDisposable
中实现
IApi
那么就会的。例如以下内容:

public class Api(HttpClient client) : IApi, IDisposable
{
    public HttpClient HttpClient => client;

    public void Dispose()
    {
        client.Dispose();
    }
}

可能会导致在正确完成处理请求之前处置

HttpClient

var serviceCollection = new ServiceCollection();
serviceCollection.AddHttpClient<IApi, Api>();
var serviceProvider = serviceCollection.BuildServiceProvider();

IApi? service;
using (var sp = serviceProvider.CreateScope())
{
    service = sp.ServiceProvider.GetService<IApi>();
}

var serviceHttpClient = service.HttpClient;
// prints "True" for the previous implementation 
Console.WriteLine(typeof(HttpClient).GetField("_disposed", BindingFlags.Instance |BindingFlags.NonPublic).GetValue(serviceHttpClient));
© www.soinside.com 2019 - 2024. All rights reserved.