package com.sungardas.enhancedsnapshots.cluster; import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.model.DeleteMessageRequest; import com.amazonaws.services.sqs.model.Message; import com.amazonaws.services.sqs.model.ReceiveMessageRequest; import com.sungardas.enhancedsnapshots.aws.dynamodb.model.NodeEntry; import com.sungardas.enhancedsnapshots.aws.dynamodb.repository.EventsRepository; import com.sungardas.enhancedsnapshots.aws.dynamodb.repository.NodeRepository; import com.sungardas.enhancedsnapshots.components.ConfigurationMediator; import com.sungardas.enhancedsnapshots.util.SystemUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @Service @DependsOn("ClusterConfigurationService") public class AutoScalingEventListener implements Runnable { private static final Logger LOG = LogManager.getLogger(AutoScalingEventListener.class); @Autowired private AmazonSQS amazonSQS; @Autowired private ClusterEventPublisher clusterEventPublisher; @Autowired private NodeRepository nodeRepository; @Autowired private ConfigurationMediator configurationMediator; @Autowired private EventsRepository eventsRepository; private static final String ESS_QUEUE_NAME = "ESS-" + SystemUtils.getSystemId() + "-queue"; private boolean receiveMessages = false; private ExecutorService executor; @Value("${enhancedsnapshots.default.polling.rate}") private int pollingRate; public void run() { while (receiveMessages) { try { ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(getQueueUrl()); List<Message> messages = amazonSQS.receiveMessage(receiveMessageRequest).getMessages(); for (Message message : messages) { JSONObject obj = new JSONObject(message.getBody()); String msg = obj.get("Message").toString(); JSONObject jsonMessage = new JSONObject(msg); if (jsonMessage.has("Event")) { AutoScalingEvents event = AutoScalingEvents.fromString((String) jsonMessage.get("Event")); switch (event) { case EC2_INSTANCE_TERMINATE: { if (eventsRepository.findOne(message.getMessageId()) == null) { clusterEventPublisher.nodeTerminated((String) jsonMessage.get("EC2InstanceId"), message.getMessageId()); amazonSQS.deleteMessage(new DeleteMessageRequest() .withQueueUrl(getQueueUrl()).withReceiptHandle(message.getReceiptHandle())); } break; } default: { LOG.warn("New AutoScaling event: {}", message.toString()); amazonSQS.deleteMessage(new DeleteMessageRequest() .withQueueUrl(getQueueUrl()).withReceiptHandle(message.getReceiptHandle())); } } } else { LOG.warn("Unknown event: {}", message.toString()); amazonSQS.deleteMessage(new DeleteMessageRequest() .withQueueUrl(getQueueUrl()).withReceiptHandle(message.getReceiptHandle())); } } } catch (Exception e) { LOG.error("Unable to process AutoScaling event", e); } sleep(); } } @PostConstruct public void startListener() { if (configurationMediator.isClusterMode()) { executor = Executors.newSingleThreadExecutor(); receiveMessages = true; executor.execute(this); LOG.info("Listener for queue: {} started.", ESS_QUEUE_NAME); } } @PreDestroy public void stopListener() { if (executor != null) { receiveMessages = false; executor.shutdownNow(); LOG.info("Listener for queue: {} stoped.", ESS_QUEUE_NAME); } } private void sleep() { try { TimeUnit.MILLISECONDS.sleep(pollingRate); } catch (InterruptedException e) { e.printStackTrace(); } } private String getQueueUrl() { return amazonSQS.getQueueUrl(ESS_QUEUE_NAME).getQueueUrl(); } public enum AutoScalingEvents { EC2_INSTANCE_LAUNCH("autoscaling:EC2_INSTANCE_LAUNCH"), EC2_INSTANCE_LAUNCH_ERROR("autoscaling:EC2_INSTANCE_LAUNCH_ERROR"), EC2_INSTANCE_TERMINATE("autoscaling:EC2_INSTANCE_TERMINATE"), EC2_INSTANCE_TERMINATE_ERROR("autoscaling:EC2_INSTANCE_TERMINATE_ERROR"), UNKNOWN("unknown"); public String getAutoScalingEvent() { return autoScalingEvent; } private final String autoScalingEvent; AutoScalingEvents(String event) { this.autoScalingEvent = event; } public static AutoScalingEvents fromString(String text) { if (text != null) { for (AutoScalingEvents autoScalingEvents : AutoScalingEvents.values()) { if (text.equalsIgnoreCase(autoScalingEvents.autoScalingEvent)) { return autoScalingEvents; } } } return UNKNOWN; } } private boolean isMasterNode(String instanceId) { NodeEntry node = nodeRepository.findOne(instanceId); return node != null && node.isMaster(); } }