c# - c# microsoft graph api getAsync() 中的 windows 服务调用用户进入挂起状态
问题描述
我正在使用 MS graph api 使用线程读取 Windows 服务中的不同邮箱。服务运行好几天,但之后进入挂起状态。
通过观察日志发现卡点是在为用户GetAsync()
调用方法时,之后它也没有更新日志文件但服务显示为运行状态。
重新启动服务后,它会正常运行几天。
public static async Task MainAsync()
{
Task t1 = ParallelThreadOne.MainAsync();
Task t2 = ParallelThreadSecond.MainAsync();
Task t3 = ParallelThreadThird.MainAsync();
await Task.WhenAll(t1, t2, t3);
}
public static async Task MainAsync()
{
try
{
EmailMaster objEmailMaster = new EmailMaster();
List<MailBoxConfiguration> lstMailBoxConfiguration = objEmailMaster.GetMailBoxInformation(1,logger);
if (lstMailBoxConfiguration != null)
{
if (lstMailBoxConfiguration.Count != 0)
{
GraphServiceClient client = GetAuthenticatedClient();
if (client != null)
{
for (int j = 0; j < lstMailBoxConfiguration.Count; j++)
{
var users = await graphClient
.Users
.Request()
.Filter("startswith(Mail,'" + lstMailBoxConfiguration[j].EmailId + "')")
.GetAsync();
if (users.Count > 0)
{
var msgs = await graphClient
.Users[users[0].Id]
.MailFolders["Inbox"].Messages
.Request().Top(500)
.GetAsync();
if (msgs.Count > 0)
{
foreach (var item in msgs)
{
//business logic goes here
}
}
else
{
logger.Info("msg.Count is zero");
}
}
else
{
logger.Info("users.Count is zero");
}
}
}
else
{
logger.Info("client is null");
}
}
else
{
logger.Info("lstMailBoxConfiguration.Count is zero from the database");
}
}
else
{
logger.Info("lstMailBoxConfiguration is null from the database");
}
logger.Info("MainAsync(1) : End of MainAsync(1)");
}
catch (Exception ex)
{
logger.Error("MainAsync(1) : Exception : " + ex.Message);
}
}
public static GraphServiceClient GetAuthenticatedClient()
{
string clientId = ConfigurationManager.AppSettings["AzureClientId"];
string password = ConfigurationManager.AppSettings["password"];
string tenantId = ConfigurationManager.AppSettings["tenantId"];
string getTokenUrl = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
const string grantType = "client_credentials";
const string myScopes = "https://graph.microsoft.com/.default";
string postBody = $"client_id={clientId}&scope={myScopes}&client_secret={password}&grant_type={grantType}";
try
{
if (graphClient == null)
{
graphClient = new GraphServiceClient(
"https://graph.microsoft.com/v1.0",
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, getTokenUrl);
httpRequestMessage.Content = new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpResponseMessage httpResponseMessage = await client.SendAsync(httpRequestMessage);
string responseBody = await httpResponseMessage.Content.ReadAsStringAsync();
userToken = JObject.Parse(responseBody).GetValue("access_token").ToString();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", userToken);
}));
}
return graphClient;
}
catch (Exception ex)
{
logger.Error("Could not create a graph client: " + ex.Message);
}
finally
{
logger.Info("GetAuthenticatedClient() :inside finally!");
}
return graphClient;
}
解决方案
通过查看 的源代码GraphServiceClient
,它被HTTPClient
用作其底层通信提供者。有一个问题,因为在HTTPClient
处理后,Windows 会在一定时间内保持 TCP/IP 连接打开HTTPClient
。如果你调用new
然后dispose
在HTTPClient
课堂上足够快足够长的时间,它可能会导致套接字饥饿。(注意,当实例超出范围时,会在后台using(var client = new HTTPClient())
调用)dispose
看看这个关于这个问题的博客文章。 https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
GraphServiceClient
只要您与同一个 GraphQL 端点通信并解决服务挂起的问题,您就应该能够使用 的单个实例。如果您添加日志记录,您可能会注意到服务在一系列活动后挂起,导致GraphServiceClient
创建大量新实例,然后在短时间内处理,并且服务器上的开放网络连接爆炸导致错误导致其中一个崩溃你的线程。
推荐阅读
- node.js - ts-node-dev 没有正确重新加载子模块
- python - 从字典创建数据框时优化性能
- reactjs - 如何在 Laravel 中创建一个 React 包并在不发布的情况下重用其组件?
- html - 我需要使用 CSS 和/或引导程序来减小移动设备的框和图像大小
- python-sphinx - 如何连续编号 Sphinx 中的方程(不同的 rst 文件)
- barbajs - 导航到慢速网络上的其他页面时页面重新加载。巴巴.js
- lua - Roblox:如何编写 VectorForce 脚本
- pandas - 对 col 名称进行模糊搜索的 pandas fillna
- javascript - 使用节点 js / javascript 切片数组元素
- python - 函数中的命令执行,名称错误 - python3