diff --git a/CHANGELOG.md b/CHANGELOG.md
index 185b0bf6..c111ca68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
## Release History
+### 1.15.0-beta.1 (Unreleased)
+#### New Features
+
+#### Key Bug Fixes
+* Fixed an issue where only 1 task run successfully when `CosmosDBSourceConnector` is configured with `maxTasks` larger than `1` - [PR 561](https://github.com/microsoft/kafka-connect-cosmosdb/pull/561)
+
+#### Other Changes
+
### 1.14.1 (2024-02-29)
#### Key Bug Fixes
* Fixed `NullPointerException` in `CosmosDBSourceConnector`. [PR 555](https://github.com/microsoft/kafka-connect-cosmosdb/pull/555)
diff --git a/pom.xml b/pom.xml
index 78d12178..1aba590b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
com.azure.cosmos.kafka
kafka-connect-cosmos
- 1.14.1
+ 1.15.0-beta.1
kafka-connect-cosmos
https://github.com/microsoft/kafka-connect-cosmosdb
diff --git a/src/main/java/com/azure/cosmos/kafka/connect/implementations/CosmosClientStore.java b/src/main/java/com/azure/cosmos/kafka/connect/implementations/CosmosClientStore.java
new file mode 100644
index 00000000..b1d626f0
--- /dev/null
+++ b/src/main/java/com/azure/cosmos/kafka/connect/implementations/CosmosClientStore.java
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.cosmos.kafka.connect.implementations;
+
+import com.azure.cosmos.ConsistencyLevel;
+import com.azure.cosmos.CosmosAsyncClient;
+import com.azure.cosmos.CosmosClientBuilder;
+import com.azure.cosmos.kafka.connect.source.CosmosDBSourceConfig;
+import org.apache.commons.lang3.StringUtils;
+
+import static com.azure.cosmos.implementation.guava25.base.Preconditions.checkArgument;
+
+public class CosmosClientStore {
+ public static CosmosAsyncClient getCosmosClient(CosmosDBSourceConfig config, String userAgentSuffix) {
+ checkArgument(StringUtils.isNotEmpty(userAgentSuffix), "Argument 'userAgentSuffix' can not be null");
+
+ CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder()
+ .endpoint(config.getConnEndpoint())
+ .key(config.getConnKey())
+ .consistencyLevel(ConsistencyLevel.SESSION)
+ .contentResponseOnWriteEnabled(true)
+ .connectionSharingAcrossClientsEnabled(config.isConnectionSharingEnabled())
+ .userAgentSuffix(userAgentSuffix);
+
+ if (config.isGatewayModeEnabled()) {
+ cosmosClientBuilder.gatewayMode();
+ }
+
+ return cosmosClientBuilder.buildAsyncClient();
+ }
+}
diff --git a/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConfig.java b/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConfig.java
index 5af36134..f028de98 100644
--- a/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConfig.java
+++ b/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConfig.java
@@ -64,6 +64,7 @@ public class CosmosDBSourceConfig extends CosmosDBConfig {
private static final String COSMOS_USE_LATEST_OFFSET_DISPLAY = "Use latest offset";
static final String COSMOS_ASSIGNED_CONTAINER_CONF = "connect.cosmos.assigned.container";
+ static final String COSMOS_ASSIGNED_LEASE_CONTAINER_CONF = "connect.cosmos.assigned.lease.container";
static final String COSMOS_WORKER_NAME_CONF = "connect.cosmos.worker.name";
static final String COSMOS_WORKER_NAME_DEFAULT = "worker";
@@ -80,6 +81,7 @@ public class CosmosDBSourceConfig extends CosmosDBConfig {
// Variables not defined as Connect configs, should not be exposed when creating connector
private String workerName;
private String assignedContainer;
+ private String assignedLeaseContainer;
public CosmosDBSourceConfig(ConfigDef config, Map parsedConfig) {
super(config, parsedConfig);
@@ -98,6 +100,7 @@ public CosmosDBSourceConfig(Map parsedConfig) {
// Since variables are not defined as Connect configs, grab values directly from Map
assignedContainer = parsedConfig.get(COSMOS_ASSIGNED_CONTAINER_CONF);
+ assignedLeaseContainer = parsedConfig.get(COSMOS_ASSIGNED_LEASE_CONTAINER_CONF);
workerName = parsedConfig.get(COSMOS_WORKER_NAME_CONF);
}
@@ -242,6 +245,10 @@ public String getAssignedContainer() {
return this.assignedContainer;
}
+ public String getAssignedLeaseContainer() {
+ return assignedLeaseContainer;
+ }
+
public String getWorkerName() {
return this.workerName;
}
diff --git a/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConnector.java b/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConnector.java
index 21f19253..0dc5615a 100644
--- a/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConnector.java
+++ b/src/main/java/com/azure/cosmos/kafka/connect/source/CosmosDBSourceConnector.java
@@ -8,6 +8,17 @@
import java.util.function.Function;
import java.util.stream.Collectors;
+
+import com.azure.cosmos.CosmosAsyncClient;
+import com.azure.cosmos.CosmosAsyncContainer;
+import com.azure.cosmos.CosmosAsyncDatabase;
+import com.azure.cosmos.CosmosException;
+import com.azure.cosmos.kafka.connect.CosmosDBConfig;
+import com.azure.cosmos.kafka.connect.implementations.CosmosClientStore;
+import com.azure.cosmos.models.CosmosContainerProperties;
+import com.azure.cosmos.models.CosmosContainerRequestOptions;
+import com.azure.cosmos.models.CosmosContainerResponse;
+import com.azure.cosmos.models.ThroughputProperties;
import org.apache.commons.lang3.RandomUtils;
import org.apache.kafka.common.config.Config;
import org.apache.kafka.common.config.ConfigDef;
@@ -28,12 +39,20 @@ public class CosmosDBSourceConnector extends SourceConnector {
private static final Logger logger = LoggerFactory.getLogger(CosmosDBSourceConnector.class);
private CosmosDBSourceConfig config = null;
+ private CosmosAsyncClient cosmosClient = null;
@Override
public void start(Map props) {
logger.info("Starting the Source Connector");
try {
config = new CosmosDBSourceConfig(props);
+ this.cosmosClient = CosmosClientStore.getCosmosClient(this.config, this.getUserAgentSuffix());
+
+ List containerList = config.getTopicContainerMap().getContainerList();
+ for (String containerId : containerList) {
+ createLeaseContainerIfNotExists(cosmosClient, this.config.getDatabaseName(), this.getAssignedLeaseContainer(containerId));
+ }
+
} catch (ConfigException e) {
throw new ConnectException(
"Couldn't start CosmosDBSourceConnector due to configuration error", e);
@@ -59,8 +78,10 @@ public List