package io.urmia.job.run;
/**
*
* Copyright 2014 by Amin Abbaspour
*
* This file is part of Urmia.io
*
* Urmia.io is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Urmia.io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Urmia.io. If not, see <http://www.gnu.org/licenses/>.
*/
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil;
import com.google.common.base.Optional;
import io.urmia.naming.model.NodeType;
import io.urmia.naming.service.NamingService;
import io.urmia.naming.service.ZkNamingServiceImpl;
import io.urmia.util.ArgumentParseUtil;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.ServiceInstanceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
private static final Executor executor = Executors.newCachedThreadPool();
private static NamingService ns;
private static ServiceInstance<NodeType> me;
private static ServiceInstance<NodeType> meWithOdsId;
private static String mountPoint;
private static String id;
private static final int AZ = 1;
private static ServiceInstance<NodeType> meWithId(ServiceInstance<NodeType> me, String id) throws Exception {
ServiceInstanceBuilder<NodeType> b = ServiceInstance.<NodeType>builder();
b.id(id)
.address(me.getAddress())
.name(me.getName())
.payload(me.getPayload())
.port(me.getPort())
//.sslPort(me.getSslPort())
.serviceType(me.getServiceType())
.uriSpec(me.getUriSpec());
return b.build();
}
public static void main(String[] args) throws Exception {
LoggerContext loggerContext = ((ch.qos.logback.classic.Logger)log).getLoggerContext();
URL mainURL = ConfigurationWatchListUtil.getMainWatchURL(loggerContext);
System.err.println(mainURL);
// or even
log.info("Logback used '{}' as the configuration file.", mainURL);
CuratorFramework client = null;
PathChildrenCache cache = null;
boolean autoRegister = ArgumentParseUtil.isAutoRegister(args);
String zkURL = ArgumentParseUtil.getZooKeeperURL(args);
log.info("starting with zk at: {}, auto register: {}", zkURL, autoRegister);
ns = new ZkNamingServiceImpl(zkURL, AZ);
Optional<ServiceInstance<NodeType>> meOpt = ns.whoAmI(NodeType.JRS, autoRegister);
if(!meOpt.isPresent()) {
System.err.println("unable to find my instance. use auto register or cli-admin to add my node");
System.exit(1);
return;
}
Runtime.getRuntime().addShutdownHook(new ShutdownHook());
try {
me = meOpt.get();
log.info("my service instance: {}", me);
ServiceInstance<NodeType> ods = getMyMatchingODSInstance(me);
id = getId(ods);//me.getId();
//ns.register(me);
meWithOdsId = meWithId(me, id);
ns.register(meWithOdsId);
mountPoint = getMountPoint(ods);
String zkPath = getPath(AZ, id);
System.err.println("instance id: " + me.getId());
System.err.println("ODS q id : " + id);
System.err.println("zk path : " + zkPath);
System.err.println("mount point: " + mountPoint);
client = CuratorFrameworkFactory.newClient(zkURL, new ExponentialBackoffRetry(1000, 3));
client.start();
cache = new PathChildrenCache(client, zkPath, true);
cache.start();
cache.getListenable().addListener(new ChildrenListener(), executor);
log.info("listening path: {}", zkPath);
loopForever();
} finally {
System.err.println("finally block...");
ns.deregister(meWithOdsId);
CloseableUtils.closeQuietly(cache);
CloseableUtils.closeQuietly(client);
}
}
private final static Object lock = new Object();
private static void loopForever() {
while (!Thread.currentThread().isInterrupted()) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException ignored) {
log.info("interrupted...");
}
}
}
}
private static String getPath(int az, String location) throws UnknownHostException {
return "/urmia/" + az + "/" + location + "/jobs";
}
private static class ChildrenListener implements PathChildrenCacheListener {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
log.info("start job process for path: {}", event.getData().getPath());
executor.execute(new JobProcess(id, client, event.getData().getPath(), mountPoint, ns));
break;
default:
log.info("ignore child event: {}", event.getType());
break;
}
}
}
private static class ShutdownHook extends Thread {
@Override
public void run() {
log.info("job runner shutting down... location: {}, PID: {}", id, getPID());
try {
ns.deregister(me);
} catch (Exception e) {
log.error("unable to deregister. error: {}", e.getMessage());
}
}
public static long getPID() {
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
return Long.parseLong(processName.split("@")[0]);
}
}
private static ServiceInstance<NodeType> getMyMatchingODSInstance(ServiceInstance<NodeType> me) throws Exception {
int rc = ns.getRunningCount(me);
System.err.println("my running count: " + rc);
Optional<ServiceInstance<NodeType>> ods = ns.getOfType(NodeType.ODS, me.getAddress(), rc);
if(! ods.isPresent()) throw new RuntimeException("unable to find matching ODS at: " + me.getAddress() + ", index: " + rc);
return ods.get();
}
private static String getMountPoint(ServiceInstance<NodeType> ods) throws Exception {
return ods.getUriSpec().getParts().get(0).getValue();
}
private static String getId(ServiceInstance<NodeType> ods) throws Exception {
return ods.getId();
}
}