azure-cosmosdbspring-webflux

Create/Recreate Azure CosmosDb async client from Java reactor context


Due to company's policy, our CosmosDb keys are rotated periodically with the new keys in Azure KeyVault so we need to deal with this changing key in our Java weblfux/reactive application. From Java SDK, once a CosmosAsyncClient is created from master key there is no way to change it and we need to rebuild it with roughly the following code:

SecretAsyncClient secretAsyncClient = new SecretClientBuilder().buildAsyncClient()
...
Mono<CosmosAsyncClient> client = secretAsyncClient.getSecret(KEY_NAME).map(
  s -> s.getValue()
).map(
  key -> new CosmosClientBuilder()
                        .endpoint(HOST)
                        .key(key)
                        .buildAsyncClient()
);
return client.flatMap(
   ...
);

From the log, the getSecret() is OK but then I got:

05:25:00.597 INFO  c.a.c.i.RxDocumentClientImpl - Initializing DocumentClient [4] with serviceEndpoint [https://xxxx-cosmosdb-sql-dev.documents.azure.com:443/], connectionPolicy [ConnectionPolicy{httpNetworkRequestTimeout=PT1M, tcpNetworkRequestTimeout=PT5S, connectionMode=DIRECT, maxConnectionPoolSize=1000, idleHttpConnectionTimeout=PT1M, idleTcpConnectionTimeout=PT0S, userAgentSuffix='', throttlingRetryOptions=RetryOptions{maxRetryAttemptsOnThrottledRequests=9, maxRetryWaitTime=PT30S}, endpointDiscoveryEnabled=true, preferredRegions=[Switzerland North], multipleWriteRegionsEnabled=true, proxyType=null, inetSocketProxyAddress=null, readRequestsFallbackEnabled=true, connectTimeout=PT5S, idleTcpEndpointTimeout=PT1H, maxConnectionsPerEndpoint=130, maxRequestsPerConnection=30, tcpConnectionEndpointRediscoveryEnabled=true}], consistencyLevel [Session], directModeProtocol [Tcp]05:25:00.598 ERROR c.a.c.i.RxDocumentClientImpl - unexpected failure in initializing client.
java.lang.RuntimeException: java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-epoll-3
        at com.azure.cosmos.implementation.http.ReactorNettyClient.attemptToWarmupHttpClient(ReactorNettyClient.java:118)
        at com.azure.cosmos.implementation.http.ReactorNettyClient.createWithConnectionProvider(ReactorNettyClient.java:98)
        at com.azure.cosmos.implementation.http.HttpClient.createFixed(HttpClient.java:61)
        at com.azure.cosmos.implementation.RxDocumentClientImpl.httpClient(RxDocumentClientImpl.java:617)
        at com.azure.cosmos.implementation.RxDocumentClientImpl.<init>(RxDocumentClientImpl.java:410)
        at com.azure.cosmos.implementation.RxDocumentClientImpl.<init>(RxDocumentClientImpl.java:262)
        at com.azure.cosmos.implementation.RxDocumentClientImpl.<init>(RxDocumentClientImpl.java:230)
        at com.azure.cosmos.implementation.AsyncDocumentClient$Builder.build(AsyncDocumentClient.java:243)
        at com.azure.cosmos.CosmosAsyncClient.<init>(CosmosAsyncClient.java:129)
        at com.azure.cosmos.CosmosClientBuilder.buildAsyncClient(CosmosClientBuilder.java:779)

So it seems that I need to put the CosmosClientBuilder().buildAsyncClient() part to an executor pool? Is there any simpler or more elegant way to do this?


Solution

  • As I explained here, Cosmos DB SDK client creates a lot of connections because of the nature of distributed systems. Warmup is a functionality that needs to be implemented in the client creation.

    Regarding your original problem of rotating keys, I provided the details here - https://github.com/Azure/azure-sdk-for-java/issues/40051#issuecomment-2097118239

    You can use AzureKeyCredential interface which allows to rotate the keys without the need for re-creating the client every time. https://azuresdkdocs.blob.core.windows.net/$web/java/azure-cosmos/latest/com/azure/cosmos/CosmosClientBuilder.html#credential(com.azure.core.credential.AzureKeyCredential)