C# BotFramework中的随机超时/任务取消异常 问题描述
我们已经将聊天机器人作为一项应用服务部署到Azure云上,在Application Insights中,我们看到一些类型为C# BotFramework中的随机超时/任务取消异常 问题描述,c#,.net,azure,async-await,botframework,C#,.net,Azure,Async Await,Botframework,我们已经将聊天机器人作为一项应用服务部署到Azure云上,在Application Insights中,我们看到一些类型为TaskCanceledException的异常会随机弹出 在查看了日志之后,我们确定了三行代码,它们引发了异常。我已经将它们标记为TaskCanceledException-source。以下是我们的消息传递控制器的简化结构,以供参考: public async Task<IHttpActionResult> Post([FromBody]BotActivity
TaskCanceledException
的异常会随机弹出
在查看了日志之后,我们确定了三行代码,它们引发了异常。我已经将它们标记为TaskCanceledException-source
。以下是我们的消息传递控制器的简化结构,以供参考:
public async Task<IHttpActionResult> Post([FromBody]BotActivity activity)
{
try
{
var result = await PostInternal(activity).ConfigureAwait(false);
return result;
}
catch (Exception e)
{
Logger.Error(e);
throw;
}
}
private async Task<IHttpActionResult> PostInternal(BotActivity activity)
{
// TaskCanceledException source #1.
await SendTypingIndicator(activity).ConfigureAwait(false);
var type = activity.GetActivityType();
if (type == ActivityTypes.Message)
{
// TaskCanceledException source #2.
var flag = await LoadFlagFromBotState(activity).ConfigureAwait(false);
// Some logic slightly altering flow according to value of 'flag'.
// TaskCanceledException source #3.
await Conversation.SendAsync(activity, () => new RootDialog()).ConfigureAwait(false);
}
return Ok();
}
private async Task SendTypingIndicator(BotActivity activity)
{
var reply = activity.CreateReply();
reply.Type = ActivityTypes.Typing;
reply.Text = null;
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.ReplyToActivityAsync(reply).ConfigureAwait(false);
}
private async Task<bool> LoadFlagFromBotState(BotActivity activity)
{
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(activity);
var userData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, CancellationToken.None).ConfigureAwait(false);
var flag = userData.GetProperty<bool>("TheFlag");
if (!flag)
{
userData.SetProperty("TheFlag", true);
await botDataStore.SaveAsync(key, BotStoreType.BotUserData, userData, CancellationToken.None).ConfigureAwait(false);
await botDataStore.FlushAsync(key, CancellationToken.None).ConfigureAwait(false);
}
return flag;
}
}
公共异步任务发布([FromBody]BotActivity)
{
尝试
{
var结果=等待后内部(活动)。配置等待(错误);
返回结果;
}
捕获(例外e)
{
错误(e);
投掷;
}
}
专用异步任务后内部(BotActivity活动)
{
//TaskCanceledException源#1。
等待发送类型指示器(活动)。配置等待(false);
var type=activity.GetActivityType();
if(type==ActivityTypes.Message)
{
//TaskCanceledException源#2。
var flag=await LoadFlagFromBotState(活动)。ConfigureAwait(false);
//一些逻辑根据“flag”的值稍微改变流程。
//TaskCanceledException源#3。
wait Conversation.sendaync(activity,()=>newrootdialog()).configurewait(false);
}
返回Ok();
}
专用异步任务SendTypingIndicator(BotActivity活动)
{
var reply=activity.CreateReply();
reply.Type=ActivityTypes.Typing;
回复:Text=null;
ConnectorClient连接器=新的ConnectorClient(新Uri(activity.ServiceUrl));
wait connector.Conversations.ReplyToActivityAsync(reply).ConfigureWait(false);
}
专用异步任务LoadFlagFromBotState(BotActivity活动)
{
使用(var scope=DialogModule.BeginLifetimeScope(Conversation.Container,activity))
{
var botDataStore=scope.Resolve();
var key=地址。FromActivity(activity);
var userData=await botDataStore.LoadAsync(key,BotStoreType.BotUserData,CancellationToken.None)。ConfigureAwait(false);
var flag=userData.GetProperty(“offlag”);
如果(!标志)
{
SetProperty(“offlag”,true);
wait botDataStore.SaveAsync(key,BotStoreType.BotUserData,userData,CancellationToken.None);
wait botDataStore.FlushAsync(key,CancellationToken.None)。configurewait(false);
}
返回标志;
}
}
以下是根据应用程序洞察超时的外部依赖项的URL:
- 对于
:任务取消异常源#1
https://directline.botframework.com/v3/conversations//activities/ 所以所有的机器人状态都存储在Cosmos数据库中
- 我们的Cosmos DB实例与bot应用程序服务位于同一Azure资源组中
- 我们验证了Cosmos DB实例的可用性和吞吐量,一切似乎都井然有序
- 我们使用DirectLine作为通信通道
是随机发生的,似乎不需要执行任何特定步骤来重现该异常TaskCanceledException
- 我们试图以“正确的方式”调整
模式,例如确保我们没有混合任何同步和异步代码,并在async await
关键字所在的任何地方使用ConfigureAwait(false)await
我将非常感谢您的建议。您是否尝试增加超时时间?否,我们保留了默认的超时时间间隔,大约为1分钟。根据App Insights,这些外部调用的持续时间在大多数情况下仅为几毫秒。这将是一种查看是否需要超过一分钟或从不回复的方法。ConfigureWait(false)导致HttpContext丢失,有时可能会在预期可用时对其进行处理。有关.ConfigureAwait(false)如何影响httpcontext的更多信息,请参见以下答案: