duplicate key given in txn request while trying to remove all keys by prefix and put them again
Asked Answered
I

1

7

Trying to use coreos/jetcd for updating haproxy settings in etcd from Java-code.

What I want to achieve is:

  1. remove all endpoints for single host
  2. add an updated data for given host

I want to remove all keys by prefix and put actual data in etcd as atomic operation.

That's why I tried to use etcd transactions. My code is:

Op.DeleteOp deleteOp = Op.delete(
        fromString(prefix),
        DeleteOption.newBuilder().withPrefix(fromString(prefix)).build()
);
Txn tx = kvClient.txn().Else(deleteOp);
newKvs.forEach((k,v) -> {
    tx.Else(Op.put(fromString(k), fromString(v), DEFAULT));
});
try {
    tx.commit().get();
} catch (InterruptedException | ExecutionException e) {
    log.error("ETCD transaction failed", e);
    throw new RuntimeException(e);
}

ETCD v3 API is used (etcd v3.2.9). KVstore is initially empty and I want to add 3 records. prefix value is:

/proxy-service/hosts/example.com

and kvs is a Map:

"/proxy-service/hosts/example.com/FTP/0" -> "localhost:10021"
"/proxy-service/hosts/example.com/HTTPS/0" -> "localhost:10443"
"/proxy-service/hosts/example.com/HTTP/0" -> "localhost:10080"

An Exception happens on commit().get() line with the following root cause:

Caused by: io.grpc.StatusRuntimeException: INVALID_ARGUMENT: etcdserver: duplicate key given in txn request
    at io.grpc.Status.asRuntimeException(Status.java:526)
    at io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClose(ClientCalls.java:427)
    at io.grpc.ForwardingClientCallListener.onClose(ForwardingClientCallListener.java:41)
    at com.coreos.jetcd.internal.impl.ClientConnectionManager$AuthTokenInterceptor$1$1.onClose(ClientConnectionManager.java:267)
    at io.grpc.internal.ClientCallImpl.closeObserver(ClientCallImpl.java:419)
    at io.grpc.internal.ClientCallImpl.access$100(ClientCallImpl.java:60)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.close(ClientCallImpl.java:493)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl.access$500(ClientCallImpl.java:422)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1StreamClosed.runInContext(ClientCallImpl.java:525)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:102)
    ... 3 more

What am i doing wrong and how else can I complete several etcd changes as atomic operation?

Instigate answered 2/11, 2017 at 14:56 Comment(0)
N
0

It looks like that the operations to remove a key and then adding a new value for the same key cannot be in the same txn. According to the The etcd APIv3 documentation:

Txn processes multiple requests in a single transaction. A txn request increments the revision of the key-value store and generates events with the same revision for every completed request. It is not allowed to modify the same key several times within one txn.

Niki answered 24/8, 2018 at 18:31 Comment(2)
Hope this answer is helpful. If you provide more details on why you want the operations to be atomic, I may be able to provide a more detailed solution.Niki
Well, somehow. Aside from the fact that I should have been able to read ;) I have to phrase a more detailed question.Anatase

© 2022 - 2024 — McMap. All rights reserved.