Robust etcd3 java client
- Accepts/exposes protobuf-generated types directly to minimize overhead
- Simpler fluent versions of KV primitives for making async or sync requests
- Automatic retries and (re)authentication
- Resilient and scalable Lease and Watch abstractions with semantics aligned to most typical usage
- Underlying stream RPCs only kept open for as long as they are needed
- Comes with some helpful utility classes with local cache, persistent key and leader election abstractions
- Simple declarative client configuration (optional) - encapsulate per-cluster connection details in a JSON document
- Support for connecting to multi-endpoint IBM Compose etcd deployments over TLS
- Currently doesn't cover all parts of the etcd-server API, in particular those related to cluster administration such as maintenance, cluster and auth management
etcd-java requires Java 8 or higher.
Create the client. Methods are grouped into separate KvClient
, LeaseClient
and LockClient
interfaces.
KvStoreClient client = EtcdClient.forEndpoint("localhost", 2379).withPlainText().build();
KvClient kvClient = client.getKvClient();
LeaseClient leaseClient = client.getLeaseClient();
LockClient lockClient = client.getLockClient();
Put a key-value synchronously
PutResponse result = kvClient.put(key, value).sync();
Get a value asynchronously with timeout
ListenableFuture<RangeResponse> result = kvClient.get(key).timeout(5000).async();
Get all key-values with specified prefix
RangeResponse result = kvClient.get(key).asPrefix().sync();
Execute a composite transaction asynchronously
ListenableFuture<TxnResponse> result = kvClient.txnIf()
.cmpEqual(key1).version(123L)
.and().cmpGreater(key2).mod(456L)
.and().notExists(key3)
.then().delete(deleteReq).and().get(rangeReq)
.elseDo().put(putReq).and().get(rangeReq).async();
Batch operations
ListenableFuture<TxnResponse> result = kvClient.batch()
.put(putReq1).put(putReq2).delete(deleteReq).async();
In case of (connection) failure, retry with backoff until successful
ListenableFuture<DeleteRangeResponse> result = kvClient.delete(key)
.backoffRetry().async();
Watch all keys with specified prefix
Watch watch = kvClient.watch(key).asPrefix().start(myWatchObserver);
Maintain a persistent lease with a specified id
PersistentLease lease = leaseClient.maintain().leaseId(myId).start();
Maintain a persistent lease with server-assigned id and listen for changes
PersistentLease lease = leaseClient.maintain().start(myLeaseObserver);
Get all keys equal to or higher than one specified
RangeResponse result = kvClient.get(key).andHigher().sync();
Watch all keys in the store, using own executor for update callbacks
Watch watch = kvClient.watch(KvClient.ALL_KEYS)
.executor(myExecutor).start(myWatchObserver);
Watch a key starting from a specific revision, using a blocking iterator
WatchIterator watch = kvClient.watch(key).startRevision(fromRev).start();
Obtain a shared persistent lease whose life is tied to the client, and subscribe to session state changes
PersistentLease sessionLease = client.getSessionLease();
sessionLease.addStateObserver(myObserver);
Establish a named lock using the client's session lease, then release it
ByteString lockKey = lockClient.lock(name).sync().getKey();
// ...
lockClient.unlock(lockKey).sync();
Instantiate a client using a cluster configuration JSON file
KvStoreClient client = EtcdClusterConfig.fromJsonFile(filePath).getClient();
<dependency>
<groupId>com.ibm.etcd</groupId>
<artifactId>etcd-java</artifactId>
<version>0.0.18</version>
</dependency>
What about jetcd?
etcd-java was originally developed within IBM for production use. At that time jetcd was in a very early and partially-working state; we needed something robust quickly and also had some different ideas for the design and semantics of the API, particularly the watch and lease abstractions.
jetcd has since matured but we still prefer the consumability of etcd-java's API. Now that etcd-java has been open-sourced, it would be great to collaborate on further development and explore the possibility of combining the best of both clients.
The key differences are included in the bulleted feature list at the top of this README.