package com.hujiang.juice.service.utils.zookeeper;
import com.hujiang.juice.common.utils.CommonUtils;
import com.hujiang.juice.service.exception.DriverException;
import com.hujiang.juice.service.model.Host;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static com.hujiang.juice.service.config.JUICE.*;
/**
* Created by xujia on 17/3/13.
*/
@Slf4j
@Data
public class CuratorUtils {
private Host host;
private volatile String path;
private CuratorFramework client;
private ExecutorService pool;
private NodeCache nodeCache;
public String generatePath() throws Exception {
return client.getChildren().forPath(MESOS_ROOT_PATH).stream().filter(ch -> ch.startsWith(PATH_NAME)).sorted().findFirst().map(this::getFullPath).orElse(null);
}
private String getFullPath(String pathName) {
return MESOS_ROOT_PATH + HTTP_SEPERATOR + pathName;
}
public CuratorUtils(String connectString, Host host) {
this.host = host;
client = CuratorFrameworkFactory.builder()
.connectString(connectString)
.sessionTimeoutMs(10000)
.connectionTimeoutMs(10000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
client.start();
try {
path = generatePath();
if (null == path) {
log.error("init curator failed due to path is null!");
throw new DriverException("init curator failed due to path is null, servie will down");
}
} catch (Exception e) {
log.error("CuratorUtils construct failed, service will down!");
client.close();
System.exit(-1);
}
}
private void childrenCacheListenable() throws Exception {
final PathChildrenCache childrenCache = new PathChildrenCache(client, MESOS_ROOT_PATH, true);
childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
childrenCache.getListenable().addListener(
new PathChildrenCacheListener() {
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event)
throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
added();
break;
case CHILD_REMOVED:
removed(event.getData().getPath());
break;
case CHILD_UPDATED:
updated(event.getData().getPath());
break;
default:
break;
}
}
},
pool
);
}
private void added() {
try {
if (StringUtils.isBlank(path)) {
String tmpPath = generatePath();
if (StringUtils.isNotBlank(tmpPath)) {
path = tmpPath;
}
setHost();
log.info("path changed to : " + path);
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
private void removed(String changedPath) {
if (StringUtils.isNotBlank(changedPath) && changedPath.equals(path)) {
try {
path = generatePath();
log.warn("path removed : " + path);
} catch (Exception e) {
path = null;
log.error(e.getMessage());
}
}
}
private void updated(String changedPath) {
try {
if(StringUtils.isBlank(path) || path.equals(changedPath)) {
if(StringUtils.isBlank(path)) {
String tmpPath = generatePath();
if (StringUtils.isNotBlank(tmpPath)) {
path = tmpPath;
}
}
setHost();
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
private void setHost() {
try {
if (StringUtils.isNotBlank(path)) {
String connectString = getConnectString();
if (StringUtils.isNotBlank(connectString) && (null == host.getHost() || !host.getHost().equals(connectString))) {
host.setHost(connectString);
log.info("path update, update mesos host to :" + host.getHost());
}
}
} catch (Exception e) {
log.error(e.getMessage());
}
}
private String getConnectString() throws Exception {
String connection = getLeaderConnectString();
if (StringUtils.isNotBlank(connection)) {
log.info("connection -> " + connection);
return CommonUtils.fixUrl(connection);
}
return null;
}
public String getLeaderConnectString() throws Exception {
String data = getData(path);
return gson.fromJson(data, JsonInfo.PathObject.class).getConnectString();
}
private String getData(String path) throws Exception {
return new String(client.getData().forPath(path));
}
public void init() {
try {
pool = Executors.newFixedThreadPool(1);
childrenCacheListenable();
Thread.sleep(1000);
String connectString = getConnectString();
if (StringUtils.isBlank(connectString)) {
throw new DriverException("get mesos host from zk error");
}
host.setHost(connectString);
} catch (Exception e) {
String errMessage = "start curator listen failed, service will down!";
log.error(errMessage);
pool.shutdown();
System.exit(-1);
}
}
}