BotFramework中的随机超时/ TaskCanceledException

时间:2018-11-22 19:50:43

标签: c# .net azure async-await botframework

问题描述

我们已将聊天机器人作为应用程序服务部署到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;
    }
}

以下是根据Application Insights超时的外部依赖项的URL:

  • 对于TaskCanceledException source #1
    • https://directline.botframework.com/v3/conversations/<CONV_ID>/activities/<ACT_ID>
  • 对于TaskCanceledException source #2
    • https://docdb-instance-url.documents.azure.com/dbs/<DB_NAME>/colls/BotState/docs/directline:user<USER_ID>
  • 对于TaskCanceledException source #3
    • https://docdb-instance-url.documents.azure.com/dbs/<DB_NAME>/colls/BotState/docs/directline:private<CONV_ID>:<USER_ID>
    • https://docdb-instance-url.documents.azure.com/dbs/<DB_NAME>/colls/BotState/docs/directline:conversation<CONV_ID>
    • https://docdb-instance-url.documents.azure.com/dbs/<DB_NAME>/colls/BotState/docs/directline:user<USER_ID>

其他信息

  • 我们的机器人是作为Microsoft Azure云中的应用程序服务托管的。
  • 我们根据following documentation插入了自定义BotState管理器,以便所有BotState都存储在Cosmos DB中。
  • 我们的Cosmos数据库实例与机器人应用程序服务位于同一Azure资源组中。
  • 我们验证了Cosmos数据库实例的可用性和吞吐量,并且一切似乎井井有条。
  • 我们使用DirectLine作为通信渠道。
  • TaskCanceledException随机发生,似乎不需要执行任何特定步骤来重现此内容。
  • 我们尝试以“正确的方式”适应async-await模式,例如,确保不混合任何同步和异步代码,并在await的所有地方使用ConfigureAwait(false)关键字是。

结论

一段时间以来,我们一直在试图找出根本原因,但是我们不知道这里可能是什么问题。由于这里使用了Azure的PaaS,因此排除了网络问题。

我将不胜感激。

0 个答案:

没有答案