为什么DocumentDbBotDataStore不会导致死锁?

时间:2018-06-10 05:34:37

标签: c# .net async-await botframework

announcement之后,即过时的机器人状态管理将被弃用,Microsoft已提供the documentation解释如何设置自定义BotState数据提供程序。

这是我根据文档插入自定义BotState提供程序的方式:

protected void Application_Start()
{
    var uri = new Uri(ConfigurationManager.AppSettings["DocumentDbUrl"]);
    var key = ConfigurationManager.AppSettings["DocumentDbKey"];
    var store = new DocumentDbBotDataStore(uri, key);

    Conversation.UpdateContainer(builder =>
    {
        builder.Register(c => store)
            .Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
            .AsSelf()
            .SingleInstance();

        builder.Register(c => new CachingBotDataStore(store, CachingBotDataStoreConsistencyPolicy.ETagBasedConsistency))
            .As<IBotDataStore<BotData>>()
            .AsSelf()
            .InstancePerLifetimeScope();

    });
}

现在,如果我们看看DocumentDbBotDataStore构造函数,它是可用的on GitHub

public DocumentDbBotDataStore(Uri serviceEndpoint, string authKey, string databaseId = "botdb", string collectionId = "botcollection")
    : this(new DocumentClient(serviceEndpoint, authKey), databaseId, collectionId) { }

public DocumentDbBotDataStore(IDocumentClient documentClient, string databaseId = "botdb", string collectionId = "botcollection")
{
    SetField.NotNull(out this.databaseId, nameof(databaseId), databaseId);
    SetField.NotNull(out this.collectionId, nameof(collectionId), collectionId);

    this.documentClient = documentClient;
    this.databaseId = databaseId;
    this.collectionId = collectionId;

    CreateDatabaseIfNotExistsAsync().GetAwaiter().GetResult();
    CreateCollectionIfNotExistsAsync().GetAwaiter().GetResult();
}

您可以看到使用CreateDatabaseIfNotExistsAsync调用同步调用异步方法CreateDatabaseIfNotExistsAsyncGetAwaiter() .GetResult(),这会导致死锁。 Here is这两种方法的实现如何:

private async Task CreateDatabaseIfNotExistsAsync()
{
    try
    {
        await documentClient.ReadDatabaseAsync(UriFactory.CreateDatabaseUri(databaseId));
    }
    catch (DocumentClientException e)
    {
        if (e.StatusCode == HttpStatusCode.NotFound)
        {
            await documentClient.CreateDatabaseAsync(new Database { Id = databaseId });
        }
        else
        {
            throw;
        }
    }
}

正如您所看到的,甚至没有调用ConfigureAwait(false)来降低死锁风险。

问题:

这个设置怎么可能从未导致死锁?

1 个答案:

答案 0 :(得分:0)

保证仅在应用程序域的生命周期内调用

Application_Start 一次:https://msdn.microsoft.com/en-us/library/ms178473.aspx#Anchor_1

Application_Start 中创建数据库和集合是安全的。