package netflix.karyon;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.netflix.governator.guice.LifecycleInjectorBuilder;
import com.netflix.governator.guice.LifecycleInjectorBuilderSuite;
import com.netflix.governator.lifecycle.LifecycleManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import rx.functions.Action0;
import javax.annotation.PostConstruct;
/**
* Provide shutdown listener as Governator managed service. Default shutdown action
* destroys Governator container. A user can provide additional actions to be run
* either before or after the container shutdown.
*
* @author Tomasz Bak
*/
public class ShutdownModule extends AbstractModule {
public static final int DEFAULT_PORT = 7002;
private final int port;
@Inject
public ShutdownModule() {
port = DEFAULT_PORT;
}
protected ShutdownModule(int port) {
this.port = port;
}
@Override
protected void configure() {
bind(Integer.class).annotatedWith(Names.named("shutdownPort")).toInstance(port);
bind(ShutdownServer.class).asEagerSingleton();
}
protected LinkedBindingBuilder<Action0> bindBeforeShutdownAction() {
return bind(Action0.class).annotatedWith(Names.named("beforeShutdownAction"));
}
protected LinkedBindingBuilder<Action0> bindAfterShutdownAction() {
return bind(Action0.class).annotatedWith(Names.named("afterShutdownAction"));
}
public static LifecycleInjectorBuilderSuite asSuite() {
return asSuite(7002);
}
public static LifecycleInjectorBuilderSuite asSuite(final int port) {
return new LifecycleInjectorBuilderSuite() {
@Override
public void configure(LifecycleInjectorBuilder builder) {
builder.withAdditionalModules(new ShutdownModule(port));
}
};
}
@Singleton
public static class ShutdownServer {
private static final Logger logger = LoggerFactory.getLogger(ShutdownServer.class);
@Inject
@Named("shutdownPort")
private int port;
@Inject(optional = true)
@Named("beforeShutdownAction")
private Action0 beforeAction;
@Inject(optional = true)
@Named("afterShutdownAction")
private Action0 afterAction;
@Inject
private LifecycleManager lifeCycleManager;
private ShutdownListener shutdownListener;
@PostConstruct
public void start() {
shutdownListener = new ShutdownListener(port, new Action0() {
@Override
public void call() {
logger.info("Shutdown request received on port {}; stopping all services...", port);
try {
runShutdownCommands();
} catch (Exception e) {
logger.error("Errors during shutdown", e);
} finally {
try {
shutdownListener.shutdown();
} catch (Exception e) {
logger.error("Errors during stopping shutdown listener", e);
}
}
}
});
shutdownListener.start();
}
private void runShutdownCommands() {
try {
if (beforeAction != null) {
beforeAction.call();
}
} finally {
try {
lifeCycleManager.close();
} finally {
if (afterAction != null) {
afterAction.call();
}
}
}
}
}
}