package org.gbif.checklistbank.cli.common;
import org.gbif.checklistbank.config.GangliaConfiguration;
import org.gbif.checklistbank.config.MetricModule;
import org.gbif.checklistbank.service.mybatis.guice.ChecklistBankServiceMyBatisModule;
import org.gbif.checklistbank.service.mybatis.guice.InternalChecklistBankServiceMyBatisModule;
import org.gbif.common.messaging.DefaultMessagePublisher;
import org.gbif.common.messaging.MessageListener;
import org.gbif.common.messaging.api.Message;
import org.gbif.common.messaging.api.MessageCallback;
import org.gbif.common.messaging.api.MessagePublisher;
import org.gbif.common.messaging.config.MessagingConfiguration;
import java.io.IOException;
import java.util.List;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.jvm.FileDescriptorRatioGauge;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AbstractIdleService;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A base service that provides convenience methods to interact with rabbit and can set up a ganglia reported metric registry.
* A hikari db pool is properly closed at the end if needed.
* @param <T>
*/
public abstract class RabbitBaseService<T extends Message> extends AbstractIdleService implements MessageCallback<T> {
private static final Logger LOG = LoggerFactory.getLogger(RabbitBaseService.class);
private final MessagingConfiguration mCfg;
private final int poolSize;
private final String queue;
private final Injector injector;
private MetricRegistry registry;
protected HikariDataSource hds;
protected MessagePublisher publisher;
protected MessageListener listener;
public RabbitBaseService(String queue, int poolSize, MessagingConfiguration mCfg, GangliaConfiguration gCfg, List<Module> modules) {
this.mCfg = mCfg;
this.poolSize = poolSize;
this.queue = queue;
injector = Guice.createInjector(ImmutableList.<Module>builder()
.add(new MetricModule(gCfg))
.addAll(modules)
.build());
this.registry = injector.getInstance(MetricRegistry.class);
initMetrics(this.registry);
// keep a reference to the hikari pool so we can close it properly on shutdown
for (Module m : modules) {
if (m instanceof ChecklistBankServiceMyBatisModule || m instanceof InternalChecklistBankServiceMyBatisModule) {
hds = (HikariDataSource) getInstance(InternalChecklistBankServiceMyBatisModule.DATASOURCE_KEY);
break;
}
}
}
public RabbitBaseService(String queue, int poolSize, MessagingConfiguration mCfg, GangliaConfiguration gCfg, Module ... modules) {
this(queue, poolSize, mCfg, gCfg, Lists.newArrayList(modules));
}
public MetricRegistry getRegistry() {
return registry;
}
public Injector injector() {
return injector;
}
public <T> T getInstance(Class<T> clazz) {
return injector.getInstance(clazz);
}
public <T> T getInstance(Key<T> key) {
return injector.getInstance(key);
}
protected String regName(String name) {
return queue + "." + name;
}
/**
* Binds metrics to an existing metrics registry.
* override this method to add more service specific metrics
*/
protected void initMetrics(MetricRegistry registry) {
registry.registerAll(new MemoryUsageGaugeSet());
registry.register(Metrics.OPEN_FILES, new FileDescriptorRatioGauge());
}
@Override
protected void startUp() throws Exception {
publisher = new DefaultMessagePublisher(mCfg.getConnectionParameters());
// dataset messages are slow, long running processes. Only prefetch one message
listener = new MessageListener(mCfg.getConnectionParameters(), 1);
startUpBeforeListening();
listener.listen(queue, poolSize, this);
}
/**
* Hook to bind startup code to that gets executed before the listener actually starts listening to messages!
*/
protected void startUpBeforeListening() throws Exception {
// dont do anything by default
}
@Override
protected void shutDown() throws Exception {
if (hds != null) {
hds.close();
}
if (listener != null) {
listener.close();
}
if (publisher != null) {
publisher.close();
}
}
protected void send(Message msg) throws IOException {
try {
LOG.info("Sending {}", msg.getClass().getSimpleName());
publisher.send(msg);
} catch (IOException e) {
LOG.error("Could not send {}", msg.getClass().getSimpleName(), e);
throw e;
}
}
}