You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将CosmosClient.CreateAndInitializeAsync()与Build()结合预热缓存?

问题背景与代码咨询

在某视频的27分20秒处提到,可通过填充路由信息缓存避免Cosmos DB冷启动延迟,具体方式有两种:读取已知不存在的文档,或使用CosmosClient.CreateAndInitializeAsync()。

我现有如下创建容器的代码:

private async Task<Container> CreateContainerAsync(string endpoint, string authKey)
{
    var cosmosClientBuilder = new CosmosClientBuilder(
            accountEndpoint: endpoint,
            authKeyOrResourceToken: authKey)
        .WithConnectionModeDirect(portReuseMode: PortReuseMode.PrivatePortPool, idleTcpConnectionTimeout: TimeSpan.FromHours(1))
        .WithApplicationName(UserAgentSuffix)
        .WithConsistencyLevel(ConsistencyLevel.Session)
        .WithApplicationRegion(Regions.AustraliaEast)
        .WithRequestTimeout(TimeSpan.FromSeconds(DatabaseRequestTimeoutInSeconds))
        .WithThrottlingRetryOptions(TimeSpan.FromSeconds(DatabaseMaxRetryWaitTimeInSeconds), DatabaseMaxRetryAttemptsOnThrottledRequests);

    var client = cosmosClientBuilder.Build();
    
    var databaseResponse = await CreateDatabaseIfNotExistsAsync(client).ConfigureAwait(false);
    
    var containerResponse = await CreateContainerIfNotExistsAsync(databaseResponse.Database).ConfigureAwait(false);

    return containerResponse;
}

想咨询两个问题:

  1. 能否将CosmosClient.CreateAndInitializeAsync()整合到现有代码中,实现路由缓存填充?
  2. 若上述方式不可行,以下通过读取不存在文档填充缓存的实现方式是否可行?
public class CosmosClientWrapper
{   
    public CosmosClientWrapper(IKeyVaultFacade keyVaultFacade)
    {           
        var container = CreateContainerAsync(endpoint, authenticationKey).GetAwaiter().GetResult();

        // Get a document that doesn't exist to populate the routing info:
        container.ReadItemAsync<object>(Guid.NewGuid().ToString(), PartitionKey.None).GetAwaiter().GetResult();     
    }
}

解答

1. 整合CosmosClient.CreateAndInitializeAsync()的可行方案

完全可以整合,这也是官方推荐的更优雅的冷启动优化方式。CreateAndInitializeAsync()会预先获取容器的路由信息并填充缓存,避免后续请求的冷启动延迟。

你可以修改现有代码,在确认数据库和容器存在后调用该方法完成初始化,修改后的代码示例如下:

private async Task<Container> CreateContainerAsync(string endpoint, string authKey)
{
    var cosmosClientBuilder = new CosmosClientBuilder(
            accountEndpoint: endpoint,
            authKeyOrResourceToken: authKey)
        .WithConnectionModeDirect(portReuseMode: PortReuseMode.PrivatePortPool, idleTcpConnectionTimeout: TimeSpan.FromHours(1))
        .WithApplicationName(UserAgentSuffix)
        .WithConsistencyLevel(ConsistencyLevel.Session)
        .WithApplicationRegion(Regions.AustraliaEast)
        .WithRequestTimeout(TimeSpan.FromSeconds(DatabaseRequestTimeoutInSeconds))
        .WithThrottlingRetryOptions(TimeSpan.FromSeconds(DatabaseMaxRetryWaitTimeInSeconds), DatabaseMaxRetryAttemptsOnThrottledRequests);

    var client = cosmosClientBuilder.Build();
    
    // 先确保数据库和容器已存在
    var databaseResponse = await CreateDatabaseIfNotExistsAsync(client).ConfigureAwait(false);
    var containerResponse = await CreateContainerIfNotExistsAsync(databaseResponse.Database).ConfigureAwait(false);

    // 调用CreateAndInitializeAsync预填充路由缓存
    await CosmosClient.CreateAndInitializeAsync(
        client,
        new[] { new ContainerProperties(databaseResponse.Database.Id, containerResponse.Container.Id) }
    ).ConfigureAwait(false);

    return containerResponse;
}

注意:CreateAndInitializeAsync需要传入已存在的数据库和容器ID,因此要先执行资源创建逻辑,避免因资源不存在导致初始化失败。

2. 读取不存在文档的方式是否可行?

这种方式可行,但需要注意几个问题:

  • 同步阻塞风险:在构造函数中使用.GetAwaiter().GetResult()会造成同步阻塞,在ASP.NET等有同步上下文的环境中可能引发死锁。建议改用异步工厂方法:
    public class CosmosClientWrapper
    {
        private readonly Container _container;
    
        private CosmosClientWrapper(Container container)
        {
            _container = container;
        }
    
        public static async Task<CosmosClientWrapper> CreateAsync(IKeyVaultFacade keyVaultFacade)
        {
            // 从密钥库获取Cosmos配置
            var endpoint = await keyVaultFacade.GetSecretAsync("CosmosEndpoint").ConfigureAwait(false);
            var authKey = await keyVaultFacade.GetSecretAsync("CosmosAuthKey").ConfigureAwait(false);
            
            var container = await CreateContainerAsync(endpoint, authKey).ConfigureAwait(false);
            
            // 读取不存在的文档填充缓存,捕获预期的404异常
            try
            {
                await container.ReadItemAsync<object>(Guid.NewGuid().ToString(), PartitionKey.None).ConfigureAwait(false);
            }
            catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                // 忽略预期的资源不存在异常
            }
            
            return new CosmosClientWrapper(container);
        }
    }
    
  • 异常处理:读取不存在的文档会返回404异常,必须捕获并忽略,避免程序崩溃。
  • 效率问题:相比CreateAndInitializeAsync,这种方式会多一次无效请求,虽能达到缓存填充目的,但官方推荐优先使用前者。

内容的提问来源于stack exchange,提问作者David Klempfner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 22:01:01