All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.findwise.hydra.Main Maven / Gradle / Ivy

There is a newer version: 0.5.0
Show newest version
package com.findwise.hydra;

import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration.ConfigurationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.net.SimpleSocketServer;

import com.findwise.hydra.mongodb.MongoConnector;
import com.findwise.hydra.mongodb.MongoType;
import com.findwise.hydra.net.HttpRESTHandler;
import com.findwise.hydra.net.RESTServer;

public final class Main implements ShutdownHandler {

	private static final long KILL_DELAY = TimeUnit.SECONDS.toMillis(30);
	private final CoreConfiguration coreConfiguration;

	public Main(CoreConfiguration coreConfiguration) {
		this.coreConfiguration = coreConfiguration;
	}

	private static Logger logger = LoggerFactory.getLogger(Main.class);
	private SimpleSocketServer simpleSocketServer = null;
	private RESTServer server = null;

	private volatile boolean shuttingDown = false;

	private static Main main;

	public static void main(String[] args) {
		if (args.length > 1) {
			logger.error("Some parameters on command line were ignored.");
		}
		
		CoreConfiguration conf;
		if (args.length > 0) {
			conf = getConfiguration(args[0]);
		} else {
			conf = getConfiguration(null);
		}

		main = new Main(conf);
		main.startup();
	}

	/**
	 * This method should be used by service wrappers to properly shutdown Hydra.
	 */
	public static void stop(@SuppressWarnings("unused") String[] args) {
		if (main != null) { // No need to shut things down if main never was
			main.shutdown();
		}
	}

	public void startup() {
		ShuttingDownOnUncaughtException uncaughtExceptionHandler = new ShuttingDownOnUncaughtException(this);
		Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
		simpleSocketServer = new SimpleSocketServer((LoggerContext) LoggerFactory.getILoggerFactory(), coreConfiguration.getLoggingPort());
		simpleSocketServer.start();

		logger.info("Hydra Core creating connector, {}='{}', {}='{}'",
				DatabaseConfiguration.DATABASE_URL_PARAM, coreConfiguration.getDatabaseUrl(),
				DatabaseConfiguration.DATABASE_NAMESPACE, coreConfiguration.getNamespace());
		
		DatabaseConnector backing = new MongoConnector(coreConfiguration);
		try {
			backing.connect();
		} catch (IOException e) {
			logger.error("Unable to start", e);
			return;
		}

		Cache cache;
		if (coreConfiguration.isCacheEnabled()) {
			cache = new MemoryCache();
		} else {
			cache = new NoopCache();
		}

		CachingDocumentNIO caching = new CachingDocumentNIO(
				backing, 
				cache, 
				coreConfiguration.isCacheEnabled(),
				coreConfiguration.getCacheTimeout());

		NodeMaster nm = new NodeMaster(
				coreConfiguration,
				caching,
				new Pipeline(), 
				this);

		server = new RESTServer(coreConfiguration,
				new HttpRESTHandler(
						nm.getDocumentIO(),
						backing.getPipelineReader(), 
						null,
						coreConfiguration.isPerformanceLogging()));

		if (!server.blockingStart()) {
			if (server.hasError()) {
				logger.error("Failed to start REST server: ", server.getError());
			} else {
				logger.error("Failed to start REST server");
			}
			
			shutdown();
		}

		try {
			nm.blockingStart();
		} catch (IOException e) {
			logger.error("Unable to start "+nm.getClass().getSimpleName()+"... Shutting down.");
			shutdown();
		}
	}

	public void shutdown() {
		logger.info("Got shutdown request...");
		shuttingDown = true;
		killUnlessShutdownWithin(KILL_DELAY);

		if (simpleSocketServer != null) {
			try {
				simpleSocketServer.close();
			} catch (Exception e) {
				logger.debug("Caught exception while shutting down "+simpleSocketServer.getClass().getSimpleName()+". Was it not started?", e);
			}
		} else {
			logger.trace(simpleSocketServer.getClass().getSimpleName()+" was null");
		}

		if (server != null) {
			try {
				server.shutdown();
				return;
			} catch (Exception e) {
				logger.debug("Caught exception while shutting down the server. Was it not started?", e);
				System.exit(1);
			}
		} else {
			logger.trace("server was null");
		}
	}

	public boolean isShuttingDown() {
		return shuttingDown;
	}

	private void killUnlessShutdownWithin(long killDelay) {
		
		if (killDelay < 0) {
			return;
		}
		HydraKiller killerThread = new HydraKiller(killDelay);
		killerThread.setDaemon(true);
		killerThread.start();
	}
	
	protected static CoreConfiguration getConfiguration(String fileName) {
		try {
			if (fileName != null) {
				return new FileConfiguration(fileName);
			} else {
				return new FileConfiguration();
			}
		} catch (ConfigurationException e) {
			logger.error("Unable to read configuration", e);
			return null;
		}
	}

	private class ShuttingDownOnUncaughtException implements UncaughtExceptionHandler {

		private final ShutdownHandler shutdownHandler;

		public ShuttingDownOnUncaughtException(ShutdownHandler shutdownHandler) {
			this.shutdownHandler = shutdownHandler;
		}

		@Override
		public void uncaughtException(Thread t, Throwable e) {
			if (!shutdownHandler.isShuttingDown()) {
				logger.error("Got an uncaught exception. Shutting down Hydra", e);
				shutdownHandler.shutdown();
			} else {
				logger.error("Got exception while shutting down", e);
			}
		}
		
	}

	private class HydraKiller extends Thread {

		Logger logger = LoggerFactory.getLogger(HydraKiller.class);
		private final long killDelay;

		public HydraKiller(long killDelay) {
			this.killDelay = killDelay;
		}

		@Override
		public void run() {
			currentThread().setName(getClass().getSimpleName());

			try {
				logger.debug("Hydra will be killed in " + killDelay + "ms unless it is shut down gracefully before then");
				Thread.sleep(killDelay);
				logger.info("Failed to shutdown hydra gracefully within configured shutdown timeout. Killing Hydra now");
				System.exit(1);
			} catch (Throwable e) {
				logger.error("Caught exception in HydraKiller thread. Killing Hydra right away!", e);
				System.exit(1);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy