chore(project): 添加项目配置文件和忽略规则

- 添加 Babel 配置文件支持 ES6+ 语法转换
- 添加 ESLint 忽略规则和配置文件
- 添加 Git 忽略规则文件
- 添加 Travis CI 配置文件
- 添加 1.4.2 版本变更日志文件
- 添加 Helm 图表辅助模板文件
- 添加 Helm 忽略规则文件
This commit is contained in:
2026-03-27 17:36:48 +08:00
commit c2453d6434
1703 changed files with 277582 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2019 Seata.io Group.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.seata</groupId>
<artifactId>seata-discovery</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-discovery-etcd3</artifactId>
<name>seata-discovery-etcd3 ${project.version}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>seata-discovery-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.etcd</groupId>
<artifactId>jetcd-core</artifactId>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>io.etcd</groupId>
<artifactId>jetcd-launcher</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,31 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.seata.discovery.registry.etcd3;
import io.seata.common.loader.LoadLevel;
import io.seata.discovery.registry.RegistryProvider;
import io.seata.discovery.registry.RegistryService;
/**
* @author xingfudeshi@gmail.com
*/
@LoadLevel(name = "Etcd3", order = 1)
public class EtcdRegistryProvider implements RegistryProvider {
@Override
public RegistryService provide() {
return EtcdRegistryServiceImpl.getInstance();
}
}

View File

@@ -0,0 +1,439 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.seata.discovery.registry.etcd3;
import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.Lease;
import io.etcd.jetcd.Watch;
import io.etcd.jetcd.kv.GetResponse;
import io.etcd.jetcd.lease.LeaseTimeToLiveResponse;
import io.etcd.jetcd.options.GetOption;
import io.etcd.jetcd.options.LeaseOption;
import io.etcd.jetcd.options.PutOption;
import io.etcd.jetcd.options.WatchOption;
import io.etcd.jetcd.watch.WatchResponse;
import io.seata.common.exception.ShouldNeverHappenException;
import io.seata.common.thread.NamedThreadFactory;
import io.seata.common.util.NetUtil;
import io.seata.common.util.StringUtils;
import io.seata.config.Configuration;
import io.seata.config.ConfigurationFactory;
import io.seata.discovery.registry.RegistryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static io.netty.util.CharsetUtil.UTF_8;
/**
* @author xingfudeshi@gmail.com
*/
public class EtcdRegistryServiceImpl implements RegistryService<Watch.Listener> {
private static final Logger LOGGER = LoggerFactory.getLogger(EtcdRegistryServiceImpl.class);
private static final Configuration FILE_CONFIG = ConfigurationFactory.CURRENT_FILE_INSTANCE;
private static final String FILE_ROOT_REGISTRY = "registry";
private static final String FILE_CONFIG_SPLIT_CHAR = ".";
private static final String REGISTRY_TYPE = "etcd3";
private static final String SERVER_ADDR_KEY = "serverAddr";
private static final String REGISTRY_CLUSTER = "cluster";
private static final String DEFAULT_CLUSTER_NAME = "default";
private static final String REGISTRY_KEY_PREFIX = "registry-seata-";
private static final String FILE_CONFIG_KEY_PREFIX = FILE_ROOT_REGISTRY + FILE_CONFIG_SPLIT_CHAR + REGISTRY_TYPE + FILE_CONFIG_SPLIT_CHAR;
private static final int MAP_INITIAL_CAPACITY = 8;
private static final int THREAD_POOL_SIZE = 2;
private ExecutorService executorService;
/**
* TTL for lease
*/
private static final long TTL = 10;
/**
* interval for life keep
*/
private final static long LIFE_KEEP_INTERVAL = 5;
/**
* critical value for life keep
*/
private final static long LIFE_KEEP_CRITICAL = 6;
private static volatile EtcdRegistryServiceImpl instance;
private static volatile Client client;
private ConcurrentMap<String, Pair<Long /*revision*/, List<InetSocketAddress>>> clusterAddressMap;
private ConcurrentMap<String, Set<Watch.Listener>> listenerMap;
private ConcurrentMap<String, EtcdWatcher> watcherMap;
private static long leaseId = 0;
private EtcdLifeKeeper lifeKeeper = null;
private Future<Boolean> lifeKeeperFuture = null;
/**
* a endpoint for unit testing
*/
public static final String TEST_ENDPONT = "etcd-test-lancher-endpoint";
private EtcdRegistryServiceImpl() {
clusterAddressMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
listenerMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
watcherMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
executorService = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("registry-etcd3", THREAD_POOL_SIZE));
}
/**
* get etcd registry service instance
*
* @return instance
*/
static EtcdRegistryServiceImpl getInstance() {
if (instance == null) {
synchronized (EtcdRegistryServiceImpl.class) {
if (instance == null) {
instance = new EtcdRegistryServiceImpl();
}
}
}
return instance;
}
@Override
public void register(InetSocketAddress address) throws Exception {
NetUtil.validAddress(address);
doRegister(address);
}
/**
* do registry
*
* @param address
*/
private void doRegister(InetSocketAddress address) throws Exception {
PutOption putOption = PutOption.newBuilder().withLeaseId(getLeaseId()).build();
getClient().getKVClient().put(buildRegistryKey(address), buildRegistryValue(address), putOption).get();
}
@Override
public void unregister(InetSocketAddress address) throws Exception {
NetUtil.validAddress(address);
doUnregister(address);
}
/**
* do unregister
*
* @param address
* @throws Exception
*/
private void doUnregister(InetSocketAddress address) throws Exception {
getClient().getKVClient().delete(buildRegistryKey(address)).get();
}
@Override
public void subscribe(String cluster, Watch.Listener listener) throws Exception {
listenerMap.computeIfAbsent(cluster, key -> new HashSet<>())
.add(listener);
EtcdWatcher watcher = watcherMap.computeIfAbsent(cluster, w -> new EtcdWatcher(cluster, listener));
executorService.submit(watcher);
}
@Override
public void unsubscribe(String cluster, Watch.Listener listener) throws Exception {
Set<Watch.Listener> subscribeSet = listenerMap.get(cluster);
if (subscribeSet != null) {
Set<Watch.Listener> newSubscribeSet = subscribeSet.stream()
.filter(eventListener -> !eventListener.equals(listener))
.collect(Collectors.toSet());
listenerMap.put(cluster, newSubscribeSet);
}
watcherMap.remove(cluster).stop();
}
@Override
public List<InetSocketAddress> lookup(String key) throws Exception {
final String cluster = getServiceGroup(key);
if (cluster == null) {
return null;
}
if (!listenerMap.containsKey(cluster)) {
//1.refresh
refreshCluster(cluster);
//2.subscribe
subscribe(cluster, new Watch.Listener() {
@Override
public void onNext(WatchResponse response) {
try {
refreshCluster(cluster);
} catch (Exception e) {
LOGGER.error("etcd watch listener", e);
throw new RuntimeException(e.getMessage());
}
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onCompleted() {
}
});
}
Pair<Long, List<InetSocketAddress>> pair = clusterAddressMap.get(cluster);
return Objects.isNull(pair) ? Collections.emptyList() : pair.getValue();
}
@Override
public void close() throws Exception {
if (lifeKeeper != null) {
lifeKeeper.stop();
if (lifeKeeperFuture != null) {
lifeKeeperFuture.get(3, TimeUnit.SECONDS);
}
}
}
/**
* refresh cluster
*
* @param cluster
* @throws Exception
*/
private void refreshCluster(String cluster) throws Exception {
if (cluster == null) {
return;
}
//1.get all available registries
GetOption getOption = GetOption.newBuilder().withPrefix(buildRegistryKeyPrefix(cluster)).build();
GetResponse getResponse = getClient().getKVClient().get(buildRegistryKeyPrefix(cluster), getOption).get();
//2.add to list
List<InetSocketAddress> instanceList = getResponse.getKvs().stream().map(keyValue -> {
String[] instanceInfo = keyValue.getValue().toString(UTF_8).split(":");
return new InetSocketAddress(instanceInfo[0], Integer.parseInt(instanceInfo[1]));
}).collect(Collectors.toList());
clusterAddressMap.put(cluster, new Pair<>(getResponse.getHeader().getRevision(), instanceList));
}
/**
* get client
*
* @return client
*/
private Client getClient() {
if (client == null) {
synchronized (EtcdRegistryServiceImpl.class) {
if (client == null) {
String testEndpoint = System.getProperty(TEST_ENDPONT);
if (StringUtils.isNotBlank(testEndpoint)) {
client = Client.builder().endpoints(testEndpoint).build();
} else {
client = Client.builder().endpoints(FILE_CONFIG.getConfig(FILE_CONFIG_KEY_PREFIX + SERVER_ADDR_KEY)).build();
}
}
}
}
return client;
}
/**
* get cluster name
*
* @return
*/
private String getClusterName() {
String clusterConfigName = String.join(FILE_CONFIG_SPLIT_CHAR, FILE_ROOT_REGISTRY, REGISTRY_TYPE, REGISTRY_CLUSTER);
return FILE_CONFIG.getConfig(clusterConfigName, DEFAULT_CLUSTER_NAME);
}
/**
* create a new lease id or return a existing lease id
*/
private long getLeaseId() throws Exception {
if (0 == leaseId) {
//create a new lease
leaseId = getClient().getLeaseClient().grant(TTL).get().getID();
lifeKeeper = new EtcdLifeKeeper(leaseId);
lifeKeeperFuture = executorService.submit(lifeKeeper);
}
return leaseId;
}
/**
* build registry key
*
* @return registry key
*/
private ByteSequence buildRegistryKey(InetSocketAddress address) {
return ByteSequence.from(REGISTRY_KEY_PREFIX + getClusterName() + "-" + NetUtil.toStringAddress(address), UTF_8);
}
/**
* build registry key prefix
*
* @return registry key prefix
*/
private ByteSequence buildRegistryKeyPrefix(String cluster) {
return ByteSequence.from(REGISTRY_KEY_PREFIX + cluster, UTF_8);
}
/**
* build registry value
*
* @param address
* @return registry value
*/
private ByteSequence buildRegistryValue(InetSocketAddress address) {
return ByteSequence.from(NetUtil.toStringAddress(address), UTF_8);
}
/**
* the type etcd life keeper
*/
private class EtcdLifeKeeper implements Callable<Boolean> {
private final long leaseId;
private final Lease leaseClient;
private boolean running;
public EtcdLifeKeeper(long leaseId) {
this.leaseClient = getClient().getLeaseClient();
this.leaseId = leaseId;
this.running = true;
}
/**
* process
*/
private void process() {
for (; ; ) {
try {
//1.get TTL
LeaseTimeToLiveResponse leaseTimeToLiveResponse = this.leaseClient.timeToLive(this.leaseId, LeaseOption.DEFAULT).get();
final long tTl = leaseTimeToLiveResponse.getTTl();
if (tTl <= LIFE_KEEP_CRITICAL) {
//2.refresh the TTL
this.leaseClient.keepAliveOnce(this.leaseId).get();
}
TimeUnit.SECONDS.sleep(LIFE_KEEP_INTERVAL);
} catch (Exception e) {
LOGGER.error("EtcdLifeKeeper", e);
throw new ShouldNeverHappenException("failed to renewal the lease.");
}
}
}
/**
* stop this task
*/
public void stop() {
this.running = false;
}
@Override
public Boolean call() {
if (this.running) {
process();
}
return this.running;
}
}
/**
* the type etcd watcher
*/
private class EtcdWatcher implements Runnable {
private final Watch.Listener listener;
private Watch.Watcher watcher;
private String cluster;
public EtcdWatcher(String cluster, Watch.Listener listener) {
this.cluster = cluster;
this.listener = listener;
}
@Override
public void run() {
Watch watchClient = getClient().getWatchClient();
WatchOption.Builder watchOptionBuilder = WatchOption.newBuilder().withPrefix(buildRegistryKeyPrefix(cluster));
Pair<Long /*revision*/, List<InetSocketAddress>> addressPair = clusterAddressMap.get(cluster);
if (Objects.nonNull(addressPair)) {
// Maybe addressPair isn't newest now, but it's ok
watchOptionBuilder.withRevision(addressPair.getKey());
}
this.watcher = watchClient.watch(buildRegistryKeyPrefix(cluster), watchOptionBuilder.build(), this.listener);
}
/**
* stop this task
*/
public void stop() {
this.watcher.close();
}
}
private static class Pair<K,V> {
/**
* Key of this <code>Pair</code>.
*/
private K key;
/**
* Value of this this <code>Pair</code>.
*/
private V value;
/**
* Creates a new pair
* @param key The key for this pair
* @param value The value to use for this pair
*/
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
/**
* Gets the key for this pair.
* @return key for this pair
*/
public K getKey() { return key; }
/**
* Gets the value for this pair.
* @return value for this pair
*/
public V getValue() { return value; }
}
}

View File

@@ -0,0 +1 @@
io.seata.discovery.registry.etcd3.EtcdRegistryProvider

View File

@@ -0,0 +1,36 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.seata.discovery.registry.etcd;
import io.seata.discovery.registry.etcd3.EtcdRegistryProvider;
import io.seata.discovery.registry.etcd3.EtcdRegistryServiceImpl;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author xingfudeshi@gmail.com
* the type etcd registry provider test
*/
public class EtcdRegistryProviderTest {
/**
* test provide
*/
@Test
public void testProvide() {
assertThat(new EtcdRegistryProvider().provide()).isInstanceOf(EtcdRegistryServiceImpl.class);
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.seata.discovery.registry.etcd;
import io.etcd.jetcd.ByteSequence;
import io.etcd.jetcd.Client;
import io.etcd.jetcd.Watch;
import io.etcd.jetcd.launcher.junit.EtcdClusterResource;
import io.etcd.jetcd.options.DeleteOption;
import io.etcd.jetcd.options.GetOption;
import io.etcd.jetcd.watch.WatchResponse;
import io.seata.discovery.registry.etcd3.EtcdRegistryProvider;
import io.seata.discovery.registry.etcd3.EtcdRegistryServiceImpl;
import io.seata.discovery.registry.RegistryService;
import org.junit.Rule;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static io.netty.util.CharsetUtil.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author xingfudeshi@gmail.com
*/
@Disabled
public class EtcdRegistryServiceImplTest {
private static final String REGISTRY_KEY_PREFIX = "registry-seata-";
private static final String CLUSTER_NAME = "default";
@Rule
private final static EtcdClusterResource etcd = new EtcdClusterResource(CLUSTER_NAME, 1);
private final Client client = Client.builder().endpoints(etcd.cluster().getClientEndpoints()).build();
private final static String HOST = "127.0.0.1";
private final static int PORT = 8091;
@BeforeAll
public static void beforeClass() throws Exception {
System.setProperty(EtcdRegistryServiceImpl.TEST_ENDPONT, etcd.cluster().getClientEndpoints().get(0).toString());
}
@AfterAll
public static void afterClass() throws Exception {
System.setProperty(EtcdRegistryServiceImpl.TEST_ENDPONT, "");
}
@Test
public void testRegister() throws Exception {
RegistryService registryService = new EtcdRegistryProvider().provide();
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//1.register
registryService.register(inetSocketAddress);
//2.get instance information
GetOption getOption = GetOption.newBuilder().withPrefix(buildRegistryKeyPrefix()).build();
long count = client.getKVClient().get(buildRegistryKeyPrefix(), getOption).get().getKvs().stream().filter(keyValue -> {
String[] instanceInfo = keyValue.getValue().toString(UTF_8).split(":");
return HOST.equals(instanceInfo[0]) && PORT == Integer.parseInt(instanceInfo[1]);
}).count();
assertThat(count).isEqualTo(1);
}
@Test
public void testUnregister() throws Exception {
RegistryService registryService = new EtcdRegistryProvider().provide();
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//1.register
registryService.register(inetSocketAddress);
//2.get instance information
GetOption getOption = GetOption.newBuilder().withPrefix(buildRegistryKeyPrefix()).build();
long count = client.getKVClient().get(buildRegistryKeyPrefix(), getOption).get().getKvs().stream().filter(keyValue -> {
String[] instanceInfo = keyValue.getValue().toString(UTF_8).split(":");
return HOST.equals(instanceInfo[0]) && PORT == Integer.parseInt(instanceInfo[1]);
}).count();
assertThat(count).isEqualTo(1);
//3.unregister
registryService.unregister(inetSocketAddress);
//4.again get instance information
getOption = GetOption.newBuilder().withPrefix(buildRegistryKeyPrefix()).build();
count = client.getKVClient().get(buildRegistryKeyPrefix(), getOption).get().getKvs().stream().filter(keyValue -> {
String[] instanceInfo = keyValue.getValue().toString(UTF_8).split(":");
return HOST.equals(instanceInfo[0]) && PORT == Integer.parseInt(instanceInfo[1]);
}).count();
assertThat(count).isEqualTo(0);
}
@Test
public void testSubscribe() throws Exception {
RegistryService registryService = new EtcdRegistryProvider().provide();
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//1.register
registryService.register(inetSocketAddress);
//2.subscribe
EtcdListener etcdListener = new EtcdListener();
registryService.subscribe(CLUSTER_NAME, etcdListener);
//3.delete instance,see if the listener can be notified
DeleteOption deleteOption = DeleteOption.newBuilder().withPrefix(buildRegistryKeyPrefix()).build();
client.getKVClient().delete(buildRegistryKeyPrefix(), deleteOption).get();
assertThat(etcdListener.isNotified()).isTrue();
}
@Test
public void testUnsubscribe() throws Exception {
RegistryService registryService = new EtcdRegistryProvider().provide();
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//1.register
registryService.register(inetSocketAddress);
//2.subscribe
EtcdListener etcdListener = new EtcdListener();
registryService.subscribe(CLUSTER_NAME, etcdListener);
//3.delete instance,see if the listener can be notified
DeleteOption deleteOption = DeleteOption.newBuilder().withPrefix(buildRegistryKeyPrefix()).build();
client.getKVClient().delete(buildRegistryKeyPrefix(), deleteOption).get();
assertThat(etcdListener.isNotified()).isTrue();
//4.unsubscribe
registryService.unsubscribe(CLUSTER_NAME, etcdListener);
//5.reset
etcdListener.reset();
//6.put instance,the listener should not be notified
client.getKVClient().put(buildRegistryKeyPrefix(), ByteSequence.from("test", UTF_8)).get();
assertThat(etcdListener.isNotified()).isFalse();
}
@Test
public void testLookup() throws Exception {
RegistryService registryService = new EtcdRegistryProvider().provide();
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//1.register
registryService.register(inetSocketAddress);
//2.lookup
List<InetSocketAddress> inetSocketAddresses = registryService.lookup("my_test_tx_group");
assertThat(inetSocketAddresses).size().isEqualTo(1);
}
/**
* build registry key prefix
*
* @return
*/
private ByteSequence buildRegistryKeyPrefix() {
return ByteSequence.from(REGISTRY_KEY_PREFIX, UTF_8);
}
/**
* etcd listener
*/
private static class EtcdListener implements Watch.Listener {
private boolean notified = false;
@Override
public void onNext(WatchResponse response) {
notified = true;
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onCompleted() {
}
/**
* @return
*/
public boolean isNotified() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
return notified;
}
/**
* reset
*/
private void reset() {
this.notified = false;
}
}
}