com.blacklocus.qs.QueueReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qs-core Show documentation
Show all versions of qs-core Show documentation
An in-jvm processing pattern for parallelized work off of a queue.
/**
* Copyright 2013 BlackLocus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.blacklocus.qs;
import com.blacklocus.misc.ExceptingRunnable;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
/**
* A more generalized version of the {@link MessageQueueReader}
*
* @param queue item type
* @param the type of queue item that this reader can convert
* @param the result of processing the converted message
* @author Jason Dunkelberger (dirkraft)
*/
public class QueueReader extends ExceptingRunnable {
private static final Logger LOG = LoggerFactory.getLogger(QueueReader.class);
/**
* default sleep time in ms between idle queue reads
*/
public static final long DEFAULT_SLEEP_MS = 20 * 1000;
protected Iterable> queueItemProvider;
protected QueueItemHandler handler;
protected ExecutorService executor;
protected long sleepMs;
/**
* Construct a new MessageQueueReader with the default idle timeout.
*
* @param provider provider to endlessly pull messages from
* @param handler handler implementation to convert and process messages
* @param executor executor service used for forking message handler processing
*/
public QueueReader(Iterable> provider,
QueueItemHandler handler,
ExecutorService executor) {
this(provider, handler, executor, DEFAULT_SLEEP_MS);
}
/**
* Construct a new MessageQueueReader with the given timeout.
*
* @param provider provider to endlessly pull messages from
* @param handler handler implementation to convert and process messages
* @param executor executor service used for forking message handler processing
* @param sleepMs how long to sleep in ms between reads from the queue where no messages are returned
*/
public QueueReader(Iterable> provider,
QueueItemHandler handler,
ExecutorService executor,
long sleepMs) {
this.queueItemProvider = provider;
this.handler = handler;
this.executor = executor;
this.sleepMs = sleepMs;
}
@Override
public void go() throws Exception {
for (Collection queueItems : queueItemProvider) {
try {
if (queueItems.size() > 0) {
for (final Q queueItem : queueItems) {
handler.withFuture(queueItem, executor.submit(new Callable>() {
public Pair call() throws Exception {
T converted = null;
R result = null;
try {
converted = handler.convert(queueItem);
result = handler.process(converted);
handler.onSuccess(queueItem, converted, result);
return Pair.of(queueItem, result);
} catch (Throwable t) {
LOG.error("An error occurred while processing item {}", queueItem, t);
handler.onError(queueItem, converted, t);
throw new RuntimeException(t);
} finally {
handler.onComplete(queueItem, converted, result);
}
}
}));
}
} else {
LOG.debug("No items available... sleeping for {} ms", sleepMs);
Thread.sleep(sleepMs);
}
} catch (InterruptedException e) {
LOG.error("Reader thread interrupted", e);
Thread.currentThread().interrupt();
} catch (Throwable t) {
LOG.error("Runtime error in reader thread", t);
}
}
}
}