Git Product home page Git Product logo

etcd-java's Introduction

Build Status

etcd-java

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.

Usage

Create the client. Methods are grouped into separate KvClient, LeaseClient, LockClient, and MaintenanceClient interfaces.

KvStoreClient client = EtcdClient.forEndpoint("localhost", 2379).withPlainText().build();


KvClient kvClient = client.getKvClient();
LeaseClient leaseClient = client.getLeaseClient();
LockClient lockClient = client.getLockClient();
MaintenanceClient maintenanceClient = client.getMaintenanceClient();

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();

Maven artifact

<dependency>
    <groupId>com.ibm.etcd</groupId>
    <artifactId>etcd-java</artifactId>
    <version>0.0.24</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.

etcd-java's People

Contributors

akirafujiu avatar alienzach avatar arnaudbos avatar dependabot[bot] avatar gi-wg2 avatar njhill avatar stevemart avatar ysohda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

etcd-java's Issues

RangeCache delete method hangs indefinitely?

Hi, Nick!
Thank you for a good job.
Seems, I've encountered a problem with RangeCache.
Sometimes, I need to delete some nodes from a range cache explicitly. So I call the remove method for that. Unfortunately, from time to time, the method hangs.

Here's the code.

@Override
protected void doStop() {
    synchronized (nodes) {
        try {
            nodes.close();
            if (localNode != null) {
                removeNode(localNode);
            }
        } catch (Exception e) {
            log.error("Can't close range cache", e);
        }
    }
 }

nodes - RangeCache instance

public void removeNode(Node node) {
    boolean deleted = nodes.delete(bs(configuration.getNodePrefixPath().concat(node.getServerId())));
    log.debug("Node is removed: {}", deleted);
}

Here's the stack trace.

"Test worker" #22 prio=5 os_prio=0 cpu=1199.21ms elapsed=147517.01s tid=0x00007fbe64bc3000 nid=0xd3193 waiting on condition  [0x00007fbe3a1b4000]
   java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
        - parking to wait for  <0x00000000e157bc10> (a com.ibm.etcd.client.GrpcClient$ThreadlessExecutor)
        at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:211)
        at com.ibm.etcd.client.GrpcClient$ThreadlessExecutor.waitAndDrain(GrpcClient.java:879)
        at com.ibm.etcd.client.GrpcClient.waitFor(GrpcClient.java:768)
        at com.ibm.etcd.client.GrpcClient.waitForCall(GrpcClient.java:729)
        at com.ibm.etcd.client.FluentRequest$AbstractFluentRequest.sync(FluentRequest.java:103)
        at com.ibm.etcd.client.utils.RangeCache.delete(RangeCache.java:844)
        at ru.ozon.platform.cluster.service.EtcdNodeRepository.removeNode(EtcdNodeRepository.java:61)
        at ru.ozon.platform.cluster.service.EtcdNodeRepository.doStop(EtcdNodeRepository.java:122)
        - locked <0x00000000e157bd18> (a com.ibm.etcd.client.utils.RangeCache)
        at com.google.common.util.concurrent.AbstractService.stopAsync(AbstractService.java:281)
        at com.google.common.util.concurrent.ServiceManager.stopAsync(ServiceManager.java:336)
        at ru.ozon.platform.common.ClusterMembershipApiIT.tearDownHost(ClusterMembershipApiIT.java:58)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
        at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
        at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke([email protected]/Method.java:564)

I suppose there's a bug in my code because I call close() before remove()?

But, is it normal behavior that code continues work and method just hang?

An additional remove method with a deadline for the whole GRPC request might help?
Or I'd expect an exception here about this abnormal situation.

What do you think?

No subject alternative DNS name matching etcd found

etcd-java version

0.0.14

Expected result

When I connect to a multi-node cluster whose hostnames appear as Subject Alternative Names in the cluster certs, the etcd-java client should honor the Subject Alternative Names during hostname validation after TLS setup.

Actual result

The etcd-java client ultimately fails, warning that no subject alternative name etcd is found:

io.grpc.StatusRuntimeException: UNAVAILABLE: io exception
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
	at io.grpc.Status.asRuntimeException(Status.java:524)
	at com.ibm.etcd.client.GrpcClient.waitFor(GrpcClient.java:748)
	at com.ibm.etcd.client.FluentRequest$AbstractFluentRequest.sync(FluentRequest.java:103)
	at com.xoom.inf.AppTest.connectTest(AppTest.java:39)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
	at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
	at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
	at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
	at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
	at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
	at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
	at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.handshakeException(ReferenceCountedOpenSslEngine.java:1728)
	at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.wrap(ReferenceCountedOpenSslEngine.java:770)
	at javax.net.ssl.SSLEngine.wrap(SSLEngine.java:509)
	at io.netty.handler.ssl.SslHandler.wrap(SslHandler.java:1043)
	at io.netty.handler.ssl.SslHandler.wrapNonAppData(SslHandler.java:934)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1392)
	at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1224)
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1271)
	at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:505)
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:444)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:283)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514)
	at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.cert.CertificateException: No subject alternative DNS name matching etcd found.
	at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:214)
	at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
	at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:459)
	at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:439)
	at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:286)
	at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144)
	at io.netty.handler.ssl.OpenSslTlsv13X509ExtendedTrustManager.checkServerTrusted(OpenSslTlsv13X509ExtendedTrustManager.java:221)
	at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:248)
	at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:699)
	at io.netty.internal.tcnative.SSL.readFromSSL(Native Method)
	at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.readPlaintextData(ReferenceCountedOpenSslEngine.java:589)
	at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1172)
	at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1289)
	at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:199)
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1329)
	... 21 more

Reproducer code:

public class AppTest {
    @Test
    public void connectTest() throws Exception {
        List<String> hosts = new ArrayList<String>();
        hosts.add("config-etcd01:2379");
        hosts.add("config-etcd02:2379");
        hosts.add("config-etcd03:2379");
        hosts.add("config-etcd04:2379");
        hosts.add("config-etcd05:2379");
        try {
            final EtcdClient client = EtcdClient.forEndpoints(hosts)
                                                .withCredentials("hello", "world")
                                                .withTlsConfig(new Consumer<SslContextBuilder>() {
                                                    @Override
                                                    public void accept(final SslContextBuilder sslContextBuilder) {
                                                    }
                                                })
                                                .build();
            KvClient kvClient = client.getKvClient();
            PutResponse result = kvClient.put(ByteString.copyFromUtf8("key"), ByteString.copyFromUtf8("value")).sync();
            final RangeResponse sync = kvClient.get(ByteString.copyFromUtf8("key")).asPrefix().sync();
            final KeyValue kvs = sync.getKvs(0);
            System.out.println(kvs.getValue());
        } catch (SSLException e) {
            e.printStackTrace();
        }
    }
}

Oddly enough, when I reduce the cluster host list from 5 members to 1 (e.g. config-etcd01), TLS setup succeeds and the test code works as expected.

These are the baseline cert Subject Alternative Names (SAN) present in each cluster node cert

DNS:config-etcd01, DNS:config-etcd02, DNS:config-etcd03, DNS:config-etcd04, DNS:config-etcd05

The node certificates do have a populated X500 DN Common Name (CN) field equal to etcd, but that does not remove the exception.

If I add etcd as an explicit SAN, the test code succeeds with a 5-member host list.

I feel like I'm missing something terribly obvious, but ask I must: what am I doing wrong?

Thanks.

memory leak

hi,I got error log about an hour after my service running.My code:

    void main(){

        KvStoreClient etcdClient = EtcdClient.forEndpoints(Arrays.asList((appProperties.getProperty("etcd.endpoints").split(","))))
                .withPlainText()
                .build();
        kvClient = etcdClient.getKvClient();
        leaseClient = etcdClient.getLeaseClient();
        leaseId = leaseClient.create(Long.valueOf(appProperties.getProperty("etcd.ttl"))).get().getID();
        etcdRegisterService();
        ScheduledFuture future = etcdKeepalive();
}

    private void etcdRegisterService() {
        String serviceName = MessageFormat.format("{0}/{1}:{2}",
                appProperties.getProperty("etcd.service.name"),
                appProperties.getProperty("etcd.service.addr"),
                appProperties.getProperty("grpc.port"));
        kvClient.put(ByteString.copyFromUtf8(serviceName),
                ByteString.copyFromUtf8(String.format("{\"Op\":0,\"Addr\":\"%s:%s\",\"Metadata\":{}}",
                        appProperties.getProperty("etcd.service.addr"),
                        appProperties.getProperty("grpc.port"))), leaseId).sync();
        logger.info("register etcd at {}", serviceName);
    }

    private ScheduledFuture etcdKeepalive() {

        TaskScheduler etcdScheduler = (TaskScheduler) applicationContext.getBean("etcdScheduler");
        return etcdScheduler.scheduleAtFixedRate(() -> {
            try {
                leaseClient.keepAliveOnce(leaseId).get();
            } catch (InterruptedException ignored) {
            } catch (Exception e) {
                logger.warn("etcd keepalive error", e);
            }
        }, Duration.ofSeconds(Long.valueOf(appProperties.getProperty("etcd.ttl")) - 3));
    }

And the error message:

2018-12-24 13:27:55.381 [etcd-event-pool-3] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
	io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:331)
	io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:185)
	io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:121)
	io.grpc.netty.NettyWritableBufferAllocator.allocate(NettyWritableBufferAllocator.java:51)
	io.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:226)
	io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.java:167)
	io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:140)
	io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:53)
	io.grpc.internal.ForwardingClientStream.writeMessage(ForwardingClientStream.java:37)
	io.grpc.internal.ClientCallImpl.sendMessage(ClientCallImpl.java:422)
	io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:37)
	io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:37)
	io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onNext(ClientCalls.java:335)
	com.ibm.etcd.client.GrpcClient$ResilientBiDiStream$RequestSubStream.sendOnNext(GrpcClient.java:413)
	com.ibm.etcd.client.GrpcClient$ResilientBiDiStream$RequestSubStream.lambda$onNext$0(GrpcClient.java:407)
	com.ibm.etcd.client.SerializingExecutor$TaskRun.run(SerializingExecutor.java:74)
	io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
	io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
	io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:326)
	io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
	io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	java.lang.Thread.run(Thread.java:748)

lib version: grpc-1.17.1-SNAPSHOT

Lease expiration managed by the PersistentLease?

Hello! I'm facing some spurious lease expiration managed by the PersistentLease even if there're no network partition or hardware overloading issue.

The problem is that, sometimes, all leases managed by PersistentLeases get expired at the etcd server side and never go back active again (or re-granted) until the etcd server restarts. Actually a persistent lease instance is not notified of LeaseState.EXPIRED state even when a lease is actually expired at the etcd server when the issue hits. Interestingly, an EXPIRED event is fired immediately followed by an ACTIVE event fired when the client is reconnected to the restarted etcd server.

I believe (from some observation and code inspection) that the persistent lease monitors lease state and re-creates expired (not closed) lease and exposes its id through PersistentLease.getLeaseID() once a lease id renewed so I send ttl request to assure the lease is OK to be related to an entity. (if ttl > 0 part) Here's roughly what I'm doing to create/refresh a PersistentLease-tied entity.

long getValidLease(PersistentLease lease) {
    validLease = -1;
    // lightly spin until I get a valid ttl response and id.
    // normally the body gets executed exactly once.
    do {
        // omitted: throw if the lease is CLOSED
        // since lease.getLeaseId() not guarantees a validness of the lease id,
        // I chose to use direct TTL request to query its state.
        ttlResp = etcdLease.ttl(lease.getLeaseId()); // lease id is updated by the event loop
        if (ttl > 0)
            validLease = ttlResp.getID();
    } while (lease.getCurrentTtlSecs() < 1); // also gets updated by the event loop
    return validLease;
}
long count(ByteString key) {
    return etcdKV.get(key).countOnly().async()
        .get(1000ms).getCount(); // 1 second timed wait-and-get
}

// operation PUT
long validLease = getValidLease(persistentLease);
etcdKV.put(key, data, validLease);

// operation REFRESH
if (count(key) == 0) {
    PUT_OPERATION(key, data); // put operation right above
}

All the entities (not many, < 20) get refreshed every 5 seconds. But after the spurious lease expiration all operations hang at the do-while loop in the getValidLease get expired lease ids through getValidLease and following operations fail because given lease id is already expired.

The etcd server looks OK: at that moment the etcd debug log shows that TTL requests from the do-while loop arrive and get answered at very high rate (due to the do-while loop) and further requests from clients (like etcdctl provided with the server distribution) get properly handled, and even granting a new lease from the same etcd-java client and making it persistent succeeds! It seems that the internal grpc client and event loop assigned with a persistent lease fail to handle responses from the server for some reason.

The issue appears randomly regardless of the server load status. As mentioned earlier, one simple solution for this is to restart the etcd server. After etcd-java reconnects to the restarted server and then all the operations work as expected again.

The etcd server (single instance configuration) is deployed in a small testbed and a spring boot application using etcd-java is also running at the same host, which means the client connects to the etcd server using localhost as the address.

Is there any recommended way dealing with the validness of a persistent lease, or am I missing something crucial?

java.lang.IllegalArgumentException: cannot find a NameResolver

Since version 0.0.15 the following exception occur when passing only a single entry in the endpoints list to the EtcdClient.forEndpoints(List<String>) method

Stacktrace
java.lang.IllegalArgumentException: cannot find a NameResolver for http://localhost:32873

	at io.grpc.internal.ManagedChannelImpl.getNameResolver(ManagedChannelImpl.java:723)
	at io.grpc.internal.ManagedChannelImpl.<init>(ManagedChannelImpl.java:605)
	at io.grpc.internal.AbstractManagedChannelImplBuilder.build(AbstractManagedChannelImplBuilder.java:517)
	at com.ibm.etcd.client.EtcdClient.<init>(EtcdClient.java:416)
	at com.ibm.etcd.client.EtcdClient$Builder.build(EtcdClient.java:334)
	at com.bertschi.gg.config.etcd.EtcdClientImpl.<init>(EtcdClientImpl.java:83)
	at com.bertschi.gg.config.etcd.WatcherTest.setUp(WatcherTest.java:39)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptLifecycleMethod(TimeoutExtension.java:126)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptBeforeEachMethod(TimeoutExtension.java:76)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeMethodInExtensionContext(ClassBasedTestDescriptor.java:481)
	at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$synthesizeBeforeEachMethodAdapter$18(ClassBasedTestDescriptor.java:466)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeEachMethods$2(TestMethodTestDescriptor.java:169)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeBeforeMethodsOrCallbacksUntilExceptionOccurs$5(TestMethodTestDescriptor.java:197)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:197)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeEachMethods(TestMethodTestDescriptor.java:166)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:133)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask$DefaultDynamicTestExecutor.execute(NodeTestTask.java:198)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:138)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.lambda$execute$2(TestTemplateTestDescriptor.java:106)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1621)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:106)
	at org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor.execute(TestTemplateTestDescriptor.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
	at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
	at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

I can workaround this by checking the size of the list on our side, before calling the builder. But I think the forEndpoints Builder should also work for a list with only one entry.

  if (endpoints.length == 1) {
      var uri = URI.create(endpoints[0]);
      this.client = com.ibm.etcd.client.EtcdClient.forEndpoint(uri.getHost(), uri.getPort())
          .withUserExecutor(this.cachedThreadPoolExecutor)
          .withPlainText()
          .build();
    } else {
      this.client = com.ibm.etcd.client.EtcdClient
          .forEndpoints(Arrays.asList(endpoints))
          .withUserExecutor(this.cachedThreadPoolExecutor)
          .withPlainText()
          .build();
    }

Lock client issue

Hello.

I am trying to integrate locking mechanism using etcd-java / LockClient.
It seems that when i create a lock using unique key i am also able to create another lock with same key, not sure maybe i am doing something wrong:

This is my code:

    ByteString uniqueKey = KeyUtils.bs("some-lock-id");
    LockResponse lr1 = lockClient.lock(uniqueKey).sync();
    LockResponse lr2 = lockClient.lock(uniqueKey).sync();

    assertTrue(lr1.isInitialized());
    ByteString lockKey1 = lr1.getKey();
    assertThat(lockKey1).isNotNull();
    assertThat(kvClient.txnIf().exists(lockKey1).sync().getSucceeded()).isTrue();

    assertTrue(lr2.isInitialized());
    ByteString lockKey2 = lr2.getKey();
    assertThat(lockKey2).isNotNull();
    assertThat(kvClient.txnIf().exists(lockKey2).sync().getSucceeded()).isTrue();

I would expect that second invocation of lockClient.lock(uniqueKey).sync() should fail since lock already exist with same key.

Thank you
-Dmitriy

Lock method, how to distinguish the success and failure of lock acquisition

LockResponse lr = client.getLockClient().lock(ByteString.copyFromUtf8(lockName)).withLease(id).sync();

lr .toString() --->
lockKey:header {
  cluster_id: 14841639068965178418
  member_id: 10276657743932975437
  revision: 58
  raft_term: 6
}
key: "123/694d7328a85b6ef9"

lockKey:header {
  cluster_id: 14841639068965178418
  member_id: 10276657743932975437
  revision: 60
  raft_term: 6
}
key: "123/694d7328a85b6efc"

how to distinguish the success and failure of lock acquisition?

Could not initialize class com.ibm.etcd.api.V3Lock

use lock has an error:

java.lang.NoClassDefFoundError: Could not initialize class com.ibm.etcd.api.V3Lock
	at com.ibm.etcd.api.LockResponse.internalGetFieldAccessorTable(LockResponse.java:97)
	at com.google.protobuf.GeneratedMessageV3.getAllFieldsMutable(GeneratedMessageV3.java:124)
	at com.google.protobuf.GeneratedMessageV3.getAllFields(GeneratedMessageV3.java:200)
	at com.alibaba.fastjson.serializer.ASMSerializer_8_LockResponse.write(Unknown Source)
	at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:312)
	at com.alibaba.fastjson.JSON.toJSONString(JSON.java:769)
	at com.alibaba.fastjson.JSON.toJSONString(JSON.java:707)

Is some source missing ?

some of the imports are from the package com.ibm.etcd.api which does not seem to be there; for example from KVClient.java
imports like these below

import com.ibm.etcd.api.PutRequest;
import com.ibm.etcd.api.PutRequestOrBuilder;
import com.ibm.etcd.api.PutResponse;
import com.ibm.etcd.api.RangeRequest;
...

Deadlock in GrpcClient

We are encountering a deadlock issue in production inside the GrpcClient#waitFor method when called from AbstractFluentRequest#sync and there is a deadline exceeded.

We managed to reproduce the issue with very short timeouts in a unit test in the following test project.

We suspect this issue was introduced with the addition of the ThreadlessExecutor and error management done in fallback logic which may return a Futures.immediateFailedFuture(t) that may not call the given executor.
This manifests as a deadlock on the waitAndDrain method here in the latest revision.

We have not been able to untangle the inner details of the issue to provide a patch, let us know if you need more investigation on our end.

Best regards

In EtcdClient.forEndpoints(xxx).withSessionTimeoutSecs(); Why is the verification completely opposite after version 0.015;

0.0.14 version:

         if (timeoutSecs < 1) {
                throw new IllegalArgumentException("invalid session timeout: " + timeoutSecs);
            }

after 0.0.15 version:

          Preconditions.checkArgument(timeoutSecs < 1, "invalid session timeout: %s", timeoutSecs);

guava:

      public static void checkArgument(boolean b, @Nullable String errorMessageTemplate, int p1) {
        if (!b) { //The time before was always 5   this is true!!!!!!!!!!!!!!
            throw new IllegalArgumentException(Strings.lenientFormat(errorMessageTemplate, new Object[]{p1}));
        }
    }

Issue with protobuf-maven-plugin

I am getting the below error 👍

 Failed to execute goal org.xolstice.maven.plugins:protobuf-maven-plugin:0.6.1:compile-custom (default) on project etcd-java: Unable to resolve artifact: Missing:
[ERROR] ----------
[ERROR] 1) io.grpc:protoc-gen-grpc-java:exe:linux-ppcle_64:1.36.1
[ERROR]
[ERROR]   Try downloading the file manually from the project website.
[ERROR]
[ERROR]   Then, install it using the command:
[ERROR]       mvn install:install-file -DgroupId=io.grpc -DartifactId=protoc-gen-grpc-java -Dversion=1.36.1 -Dclassifier=linux-ppcle_64 -Dpackaging=exe -Dfile=/path/to/file
[ERROR]
[ERROR]   Alternatively, if you host your own repository you can deploy the file there:
[ERROR]       mvn deploy:deploy-file -DgroupId=io.grpc -DartifactId=protoc-gen-grpc-java -Dversion=1.36.1 -Dclassifier=linux-ppcle_64 -Dpackaging=exe -Dfile=/path/to/file -Durl=[url] -DrepositoryId=[id]
[ERROR]
[ERROR]   Path to dependency:
[ERROR]         1) com.ibm.etcd:etcd-java:jar:0.0.19-SNAPSHOT
[ERROR]         2) io.grpc:protoc-gen-grpc-java:exe:linux-ppcle_64:1.36.1
[ERROR]
[ERROR] ----------
[ERROR] 1 required artifact is missing.
[ERROR]
[ERROR] for artifact:
[ERROR]   com.ibm.etcd:etcd-java:jar:0.0.19-SNAPSHOT
[ERROR]
[ERROR] from the specified remote repositories:
[ERROR]   central (https://repo.maven.apache.org/maven2, releases=true, snapshots=false)
[ERROR]

Test KvTest io.grpc.StatusRuntimeException: INTERNAL: Panic! This is a bug!

/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/bin/java -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=54638:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit-rt.jar:/Applications/IntelliJ IDEA.app/Contents/plugins/junit/lib/junit5-rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/lib/tools.jar:/Users/liberxue/java/etcd-java-master/target/test-classes:/Users/liberxue/java/etcd-java-master/target/classes:/Users/liberxue/.m2/repository/io/netty/netty-all/4.0.42.Final/netty-all-4.0.42.Final.jar:/Users/liberxue/.m2/repository/com/ibm/etcd/etcd-java/0.0.4/etcd-java-0.0.4.jar:/Users/liberxue/.m2/repository/io/netty/netty-transport-native-epoll/4.1.22.Final/netty-transport-native-epoll-4.1.22.Final-linux-x86_64.jar:/Users/liberxue/.m2/repository/io/netty/netty-common/4.1.22.Final/netty-common-4.1.22.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-buffer/4.1.22.Final/netty-buffer-4.1.22.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-transport-native-unix-common/4.1.22.Final/netty-transport-native-unix-common-4.1.22.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-transport/4.1.22.Final/netty-transport-4.1.22.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-resolver/4.1.22.Final/netty-resolver-4.1.22.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-tcnative-boringssl-static/2.0.7.Final/netty-tcnative-boringssl-static-2.0.7.Final.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-netty/1.16.1/grpc-netty-1.16.1.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-core/1.16.1/grpc-core-1.16.1.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-context/1.16.1/grpc-context-1.16.1.jar:/Users/liberxue/.m2/repository/io/opencensus/opencensus-api/0.12.3/opencensus-api-0.12.3.jar:/Users/liberxue/.m2/repository/io/opencensus/opencensus-contrib-grpc-metrics/0.12.3/opencensus-contrib-grpc-metrics-0.12.3.jar:/Users/liberxue/.m2/repository/io/netty/netty-codec-http2/4.1.30.Final/netty-codec-http2-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-codec-http/4.1.30.Final/netty-codec-http-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-codec/4.1.30.Final/netty-codec-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-handler/4.1.30.Final/netty-handler-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-handler-proxy/4.1.30.Final/netty-handler-proxy-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/netty/netty-codec-socks/4.1.30.Final/netty-codec-socks-4.1.30.Final.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-protobuf/1.16.1/grpc-protobuf-1.16.1.jar:/Users/liberxue/.m2/repository/com/google/protobuf/protobuf-java/3.5.1/protobuf-java-3.5.1.jar:/Users/liberxue/.m2/repository/com/google/api/grpc/proto-google-common-protos/1.0.0/proto-google-common-protos-1.0.0.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-protobuf-lite/1.16.1/grpc-protobuf-lite-1.16.1.jar:/Users/liberxue/.m2/repository/io/grpc/grpc-stub/1.16.1/grpc-stub-1.16.1.jar:/Users/liberxue/.m2/repository/com/google/code/gson/gson/2.8.5/gson-2.8.5.jar:/Users/liberxue/.m2/repository/com/google/guava/guava/26.0-jre/guava-26.0-jre.jar:/Users/liberxue/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/liberxue/.m2/repository/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.jar:/Users/liberxue/.m2/repository/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar:/Users/liberxue/.m2/repository/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar:/Users/liberxue/.m2/repository/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar:/Users/liberxue/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/liberxue/.m2/repository/junit/junit/4.12/junit-4.12.jar:/Users/liberxue/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/Users/liberxue/.m2/repository/org/slf4j/slf4j-simple/1.7.25/slf4j-simple-1.7.25.jar" com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 com.ibm.etcd.client.KvTest,testKvOps
localproxy about to start on port 10315
localproxy started on port 10315 in 66ms
Nov 23, 2018 6:19:48 PM io.grpc.internal.ChannelExecutor handleUncaughtThrowable
WARNING: Runnable threw exception in ChannelExecutor
java.lang.NoSuchMethodError: io.netty.handler.codec.http.HttpResponseStatus.codeAsText()Lio/netty/util/AsciiString;
	at io.netty.handler.codec.http2.Http2ConnectionHandler.<clinit>(Http2ConnectionHandler.java:72)
	at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:196)
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:33)
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:33)
	at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:249)
	at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:209)
	at io.grpc.internal.ManagedChannelImpl$SubchannelImpl.requestConnection(ManagedChannelImpl.java:1440)
	at io.grpc.PickFirstBalancerFactory$PickFirstBalancer.handleResolvedAddressGroups(PickFirstBalancerFactory.java:74)
	at io.grpc.internal.AutoConfiguredLoadBalancerFactory$AutoConfiguredLoadBalancer.handleResolvedAddressGroups(AutoConfiguredLoadBalancerFactory.java:137)
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl$1NamesResolved.run(ManagedChannelImpl.java:1307)
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:73)
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:1241)
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:1311)
	at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:252)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

localproxy on port 10315 about to forcibly stop
localproxy on port 10315 stopped in 11ms

io.grpc.StatusRuntimeException: INTERNAL: Panic! This is a bug!

	at io.grpc.Status.asRuntimeException(Status.java:517)
	at com.ibm.etcd.client.GrpcClient.waitFor(GrpcClient.java:642)
	at com.ibm.etcd.client.kv.EtcdKvClient$AbstractFluentRequest.sync(EtcdKvClient.java:216)
	at com.ibm.etcd.client.kv.EtcdKvClient$EtcdTxnRequest$EtcdTxnOps.sync(EtcdKvClient.java:556)
	at com.ibm.etcd.client.kv.EtcdKvClient$EtcdTxnRequest$EtcdTxnOps.sync(EtcdKvClient.java:481)
	at com.ibm.etcd.client.KvTest.testKvOps(KvTest.java:72)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.NoSuchMethodError: io.netty.handler.codec.http.HttpResponseStatus.codeAsText()Lio/netty/util/AsciiString;
	at io.netty.handler.codec.http2.Http2ConnectionHandler.<clinit>(Http2ConnectionHandler.java:72)
	at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:196)
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:33)
	at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:33)
	at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:249)
	at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:209)
	at io.grpc.internal.ManagedChannelImpl$SubchannelImpl.requestConnection(ManagedChannelImpl.java:1440)
	at io.grpc.PickFirstBalancerFactory$PickFirstBalancer.handleResolvedAddressGroups(PickFirstBalancerFactory.java:74)
	at io.grpc.internal.AutoConfiguredLoadBalancerFactory$AutoConfiguredLoadBalancer.handleResolvedAddressGroups(AutoConfiguredLoadBalancerFactory.java:137)
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl$1NamesResolved.run(ManagedChannelImpl.java:1307)
	at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:73)
	at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:1241)
	at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:1311)
	at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:252)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)


Process finished with exit code 255

Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00)
Maven home: /Users/liberxue/java/maven/apache-maven-3.5.4
Java version: 1.8.0_181, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home/jre
Default locale: en_CN, platform encoding: UTF-8
OS name: "mac os x", version: "10.14", arch: "x86_64", family: "mac"

Connection SNI settings?

As far as I can tell, the client doesn't set the SNI/servername header on its TLS/SSL connections. Where Compose etcd users TLS/SSL it requires that to be set so it can verify with the right certificate.

Currently working around with .withTrustManager(InsecureTrustManagerFactory.INSTANCE) in the connection.

Is hot reload for user and password creds available?

Greetings!

We have a task to hot reload creds to etcd (they can be changed from vault). Is it allowed in your library? How to process situations where watches on key are already set and currently listening? Should I recreate client every time creds change? How would you do this?

Thank you.

Collaborate on jetcd

At the end of the readme there is a what-about-jetcd, as one of the contributor and maintainer of the jetcd project I'd love to see if we can work together on a single client.

Support for client cert auth

Is there some documentation on how this should work?
What should the certificate file contain or which format should it have?
I mean the cert file I pass to the ComposeTrustManagerFactory.

KvStoreClient.close() doesn't release all resources

I keep on doing the following, and the memory of the JVM quickly goes up and eventually crashed due to OOM. I know it is better to reuse the KvStoreClient instance, but closing it should release all the referenced memory.

  1. Create KvStoreClient
  2. Create a KV
  3. Delete a KV
  4. Close KvStoreClient

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.