package com.widowcrawler.core.queue;
import com.amazonaws.services.sqs.AmazonSQSAsyncClient;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import com.amazonaws.services.sqs.model.SendMessageResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @author Scott Mansfield
*/
public class Enqueuer implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(Enqueuer.class);
@Inject
AmazonSQSAsyncClient sqsClient;
@Inject
ExecutorService executorService;
private static class SendMessageRequestHolder {
private SendMessageRequest sendMessageRequest;
private Future<SendMessageResult> sendMessageResultFuture;
private int tries;
public SendMessageRequestHolder(
SendMessageRequest sendMessageRequest,
Future<SendMessageResult> sendMessageResultFuture,
int tries) {
this.sendMessageRequest = sendMessageRequest;
this.sendMessageResultFuture = sendMessageResultFuture;
this.tries = tries;
}
public SendMessageRequest getSendMessageRequest() {
return sendMessageRequest;
}
public Future<SendMessageResult> getSendMessageResultFuture() {
return sendMessageResultFuture;
}
public int getTries() {
return tries;
}
}
private final LinkedBlockingQueue<SendMessageRequestHolder> enqueueActions = new LinkedBlockingQueue<>();
@PostConstruct
public void postConstruct() {
executorService.submit(this);
}
public void run() {
//noinspection InfiniteLoopStatement
while (true) {
SendMessageRequestHolder holder = null;
try {
holder = enqueueActions.take();
SendMessageResult result = holder.getSendMessageResultFuture().get();
logger.info("Message enqueued successfully. Message ID: " + result.getMessageId());
} catch (InterruptedException e) {
logger.error("Enqueuer interrupted", e);
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
logger.error("Enqueueing failed", e.getCause());
SendMessageRequest sendMessageRequest = holder.getSendMessageRequest();
if (holder.getTries() >= 5) {
String message = String.format("Giving up on message \"%s\" sent to queue %s...",
sendMessageRequest.getQueueUrl(),
sendMessageRequest.getMessageBody().substring(0, 50));
logger.error(message);
} else {
enqueue(sendMessageRequest.getQueueUrl(),
sendMessageRequest.getMessageBody(),
holder.getTries() + 1);
}
}
}
}
public void enqueue(String queueName, String messageBody) {
enqueue(queueName, messageBody, 0);
}
private void enqueue(String queueName, String messageBody, int tries) {
SendMessageRequest sendMessageRequest = new SendMessageRequest(queueName, messageBody);
Future<SendMessageResult> resultFuture = sqsClient.sendMessageAsync(sendMessageRequest);
enqueueActions.add(new SendMessageRequestHolder(sendMessageRequest, resultFuture, tries));
}
}