package cgl.iotcloud.transport.kestrel; import net.lag.kestrel.thrift.Item; import org.apache.thrift.TException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.BlockingQueue; public class KestrelConsumer { // by default we are going to black list a server for 30 secs private long blackListTime = 30000L; public static final int MAX_ITEMS = 64; public static final int WAIT_TIME = 10; private Logger logger; private KestrelThriftClient client = null; private BlockingQueue messages; private boolean run = true; private int timeoutMillis = 30000; private KestrelDestination destination; private long sleepTime = 0; public KestrelConsumer(Logger logger, KestrelDestination destination, BlockingQueue messages) { if (logger == null) { this.logger = LoggerFactory.getLogger(KestrelConsumer.class); } this.messages = messages; this.destination = destination; } public KestrelConsumer(KestrelDestination destination, BlockingQueue<KestrelMessage> messages) { this(null, destination, messages); } public void setTimeoutMillis(int timeoutMillis) { this.timeoutMillis = timeoutMillis; } public void setBlackListTime(long blackListTime) { this.blackListTime = blackListTime; } public void open() { Thread t = new Thread(new Worker()); t.start(); } public void ack(KestrelMessage message) { try { KestrelThriftClient thriftClient = getValidClient(); Set<Long> set = new HashSet<Long>(); set.add(message.getId()); thriftClient.confirm(message.getQueue(), set); } catch (TException e) { logger.error("Failed to ack the message with id {}", message.getId(), e); closeClient(); } } public void fail(KestrelMessage message) { try { KestrelThriftClient thriftClient = getValidClient(); Set<Long> set = new HashSet<Long>(); set.add(message.getId()); thriftClient.abort(message.getQueue(), set); } catch (TException e) { logger.error("Failed to abort the message with id {}", message.getId(), e); closeClient(); } } public void close() { run = false; closeClient(); } private KestrelThriftClient getValidClient() throws TException { if (client == null) { client = new KestrelThriftClient(destination.getHost(), destination.getPort()); } return client; } private void closeClient() { if (client != null) { client.close(); } } private class Worker implements Runnable { @Override public void run() { while (run) { if (System.currentTimeMillis() > sleepTime) { String q = destination.getQueue(); try { getValidClient(); } catch (TException e) { closeClient(); sleepTime = System.currentTimeMillis() + blackListTime; continue; } List<Item> items; try { items = client.get(q, MAX_ITEMS, 0, 0); if (items != null) { for (Item item :items) { byte[] bytes = item.get_data(); byte[] newBytes = Arrays.copyOf(bytes, bytes.length); KestrelMessage m = new KestrelMessage(newBytes, item.get_id(), destination, q); messages.put(m); } } } catch (TException e) { logger.debug("Error retrieving messages from queue {} and host {} port {}", q, destination.getHost(), destination.getPort()); closeClient(); sleepTime = System.currentTimeMillis() + blackListTime; } catch (InterruptedException e) { logger.error("Failed to add the message to the queue", e); } } else { try { Thread.sleep(100); } catch (InterruptedException ignored) { } } } } } }