дублировать ключ, указанный в запросе txn, при попытке удалить все ключи по префиксу и поставить их снова

Попытка использовать coreos/jetcd для обновления настроек haproxy в etcd из Java-кода.

Чего я хочу добиться, так это:

  1. удалить все конечные точки для одного хоста
  2. добавить обновленные данные для данного хоста

Я хочу удалить все ключи по префиксу и поместить фактические данные в etcd как атомарную операцию.

Вот почему я попытался использовать транзакции etcd. Мой код:

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

Используется API ETCD v3 (etcd v3.2.9). KVstore изначально пуст и я хочу добавить 3 записи. prefix значение:

/proxy-service/hosts/example.com

а kvs — карта:

"/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"

Исключение возникает в строке commit().get() со следующей основной причиной:

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

Что я делаю неправильно и как еще я могу выполнить несколько изменений etcd как атомарную операцию?


person Kirill    schedule 02.11.2017    source источник


Ответы (1)


Похоже, что операции по удалению ключа и последующему добавлению нового значения для того же ключа не могут быть в одном и том же txn. Согласно документации etcd APIv3:

Txn обрабатывает несколько запросов в одной транзакции. Запрос txn увеличивает версию хранилища ключей и значений и создает события с одной и той же версией для каждого завершенного запроса. Не допускается изменение одного и того же ключа несколько раз в рамках одного txn.

person Ghasem Naddaf    schedule 24.08.2018
comment
Надеюсь, этот ответ будет полезен. Если вы предоставите более подробную информацию о том, почему вы хотите, чтобы операции были атомарными, я смогу предоставить более подробное решение. - person Ghasem Naddaf; 24.08.2018
comment
Ну как-то. Помимо того, что я должен был уметь читать ;) я должен сформулировать более подробный вопрос. - person Markus W Mahlberg; 25.08.2018