在我的 ASP.NET Core Web API 托管服务中,我正在发出连续的 HTTP 客户端请求并使用任务同时执行 10 个请求。我遇到的问题是,一段时间后,服务挂起并停止记录任何消息。它甚至没有点击
StopAsync()
或在我记录步骤的服务的 executeAsync
方法中捕获异常。我在这里基本上一无所知。我觉得我确实在代码中处理了 http 客户端和 http 响应。
我的代码可能出了什么问题?
var users = GetUsersFromDB.ToList();
userBatches = users.Chunk(10).ToList();
var clientUserFacades = new List<ClientUserFacade>();
foreach (var UserBatch in UserBatches)
{
logger.LogMessage(LogLevel.Information, hostedServiceType, "User batch index {UserBatchNo} - Processing started", UserBatches.IndexOf(UserBatch));
try
{
var tasks = UserBatch.Select(User => clientUserSendHandler.SendUserInfoToClient(hostedServiceType, client, User, false));
var results = await Task.WhenAll(tasks);
clientUserFacades.AddRange(results.Where(p => p.IsResponseValid));
}
catch (Exception ex)
{
logger.LogMessage(LogLevel.Error, hostedServiceType, ex, "Batch processing task cancelled. Skipping the current batch. Trying after 10 seconds!");
await Task.Delay(TimeSpan.FromSeconds(10), CancellationToken.None);
continue;
}
logger.LogMessage(LogLevel.Information, hostedServiceType, "User batch index {UserBatchNo} client send completed", UserBatches.IndexOf(UserBatch));
if (UserBatches.IndexOf(UserBatch) % 50 == 0 || UserBatches.ToList().IndexOf(UserBatch) == (UserBatches.Count - 1))
{
await clientUserWriteHandler.BulkUpdateClientUserAsync(hostedServiceType, client, clientUserFacades); // database update
clientUserFacades.Clear();
logger.LogMessage(LogLevel.Information, hostedServiceType, "User batches updated to database at batch index {UserBatchNo}", UserBatches.IndexOf(UserBatch));
}
}
public async Task<ClientUserFacade> SendUserInfoToClient(HostedServiceType hostedServiceType, ClientFacade client, User User, bool includeResponseContent=false)
{
var UserName = CommonHelper.RemoveWhiteSpaceAndSpecialCharacters(User.Name);
var UserMobileNo = CommonHelper.RemoveNonNumericCharacters(User.MobileNo);
var clientUser = new ClientUserFacade
{
ClientId = client.Id,
UserId = User.Id
};
var param = new Dictionary<string, string>
{
{ "name", UserName },
{ "phone", UserMobileNo }
};
try
{
var requestUrl = new Uri(QueryHelpers.AddQueryString(client.ApiUrl, param!));
clientUser.LastRequestTimestamp = DateTime.Now.ToUniversalTime();
using var httpClient = httpClientFactory.CreateClient();
using var response = await httpClient.GetAsync(requestUrl);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
if (includeResponseContent)
{
clientUser.ResponseContent = data;
}
var responseObject = JObject.Parse(data);
ProcessClientReponse(clientUser, responseObject);
}
else
{
var logMessage = $"Request unsuccessful with response Code {(int)response.StatusCode} for client api request of User [{UserName} | {UserMobileNo}]";
LogMessage(LogLevel.Error, hostedServiceType, null, logMessage);
if (includeResponseContent && response is { })
{
clientUser.LastResponseCode = (int)response.StatusCode;
var data = await response.Content.ReadAsStringAsync();
clientUser.ResponseContent = data;
}
}
}
catch (Exception ex)
{
var logMessage = $"Unexpected error during client api request of User [{UserName} | {UserMobileNo}]";
LogMessage(LogLevel.Critical, hostedServiceType, ex, logMessage);
}
return clientUser;
}
我确实尝试为下面的任务设置超时 - 但没有运气
var tasks = userBatch.Select(async User =>
{
var sendTask = clientUserSendHandler.SendUserInfoToClient(hostedServiceType, client, User);
var timeoutTask = Task.Delay(TimeSpan.FromMinutes(5));
var completedTask = await Task.WhenAny(sendTask, timeoutTask);
if (completedTask == timeoutTask)
{
logger.LogMessage(LogLevel.Warning, hostedServiceType, $"Task for User [{User.Name} | {User.MobileNo}] cancelled after waiting for 5 mins");
return new ClientUserFacade { ClientId = client.Id, UserId = User.Id, IsResponseValid = false };
}
return await sendTask;
});
你的
var results = await Task.WhenAll(tasks);
线等待所有任务结束。但如果任务太长而无法结束怎么办?您要么需要为
tasks
中的每个任务提供超时机制,要么不要等待所有任务完成。相反,等待 WhenAny
,查看 tasks
的大小,并添加您的设置/期望认为正确的尽可能多的新任务。
您还可以有一个单独的任务,它了解您执行的任务并定期检查超时。如果您选择这样,那么您可以使用
WhenAll