C# BotFramework中的随机超时/任务取消异常 问题描述

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

我们已经将聊天机器人作为一项应用服务部署到Azure云上,在Application Insights中,我们看到一些类型为
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
      模式,例如确保我们没有混合任何同步和异步代码,并在
      await
      关键字所在的任何地方使用ConfigureAwait(false)
    结论 一段时间以来,我们一直在试图找出根本原因,但我们不知道这里可能存在什么问题。我们排除了网络问题,因为我们在这里使用Azure的PaaS


    我将非常感谢您的建议。

    您是否尝试增加超时时间?否,我们保留了默认的超时时间间隔,大约为1分钟。根据App Insights,这些外部调用的持续时间在大多数情况下仅为几毫秒。这将是一种查看是否需要超过一分钟或从不回复的方法。ConfigureWait(false)导致HttpContext丢失,有时可能会在预期可用时对其进行处理。有关.ConfigureAwait(false)如何影响httpcontext的更多信息,请参见以下答案: