/** * Copyright 2012 Comcast Corporation * * 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.comcast.cqs.test.unit; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import com.amazonaws.services.sqs.model.DeleteMessageRequest; import com.amazonaws.services.sqs.model.GetQueueAttributesRequest; import com.amazonaws.services.sqs.model.GetQueueAttributesResult; import com.amazonaws.services.sqs.model.Message; import com.amazonaws.services.sqs.model.ReceiveMessageRequest; import com.amazonaws.services.sqs.model.ReceiveMessageResult; import com.amazonaws.services.sqs.model.SendMessageRequest; import com.amazonaws.services.sqs.model.SendMessageResult; import com.comcast.cmb.test.tools.CMBAWSBaseTest; public class CQSEnduranceTest extends CMBAWSBaseTest { private static int sendDelay = 10; private static int receiveDelay = 0; private static int monitorDelay = 5000; private static int numSenders = 10; private static int numReceivers = 10; private static int maxQueueDepth = 1000; private static long maxInflightTime = 0; private static ConcurrentHashMap<String,Long> transactions = new ConcurrentHashMap<String,Long>(); private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private static String queueUrl; private static AtomicLong sendSuccessCount = new AtomicLong(0); private static AtomicLong sendFailureCount = new AtomicLong(0); private static AtomicLong receiveSuccessCount = new AtomicLong(0); private static AtomicLong receiveFailureCount = new AtomicLong(0); private static AtomicLong actualMessagesReceivedCount = new AtomicLong(0); private static AtomicLong deleteSuccessCount = new AtomicLong(0); private static AtomicLong deleteFailureCount = new AtomicLong(0); private static AtomicLong attribSuccessCount = new AtomicLong(0); private static AtomicLong attribFailureCount = new AtomicLong(0); private static String generateRandomMessage(int length) { StringBuilder sb = new StringBuilder(length); for (int i=0; i<length; i++) { sb.append(ALPHABET.charAt(rand.nextInt(ALPHABET.length()))); } return sb.toString(); } public void start() throws Exception { setup(); queueUrl = this.getQueueUrl(1, USR.USER1); logger.info("event=created_queue queue_url=" + queueUrl); ScheduledThreadPoolExecutor ep = new ScheduledThreadPoolExecutor(100); logger.info("event=launching_monitor"); ep.submit(new MonitorDaemon()); for (int i=0; i<numReceivers; i++) { logger.info("event=launching_receiver"); ep.submit(new MessageReceiver()); } for (int i=0; i<numSenders; i++) { logger.info("event=launching_sender"); ep.submit(new MessageSender()); } try { ep.shutdown(); ep.awaitTermination(100, TimeUnit.DAYS); } catch (InterruptedException ex) { logger.error("event=endurance_failure queue_url=" + queueUrl, ex); } logger.info("event=done"); } public static void main(String [ ] args) throws Exception { new CQSEnduranceTest().start(); } private static class MonitorDaemon implements Runnable { @Override public void run() { Thread.currentThread().setName("MONITOR_" + rand.nextInt(100)); while (true) { try { Thread.currentThread().sleep(monitorDelay); long start = System.currentTimeMillis(); GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(queueUrl); Set<String> attribs = new TreeSet<String>(); attribs.add("All"); getQueueAttributesRequest.setAttributeNames(attribs); GetQueueAttributesResult result = cqs1.getQueueAttributes(getQueueAttributesRequest); int numMsg = Integer.valueOf(result.getAttributes().get("ApproximateNumberOfMessages")); int numInvisible = Integer.valueOf(result.getAttributes().get("ApproximateNumberOfMessagesNotVisible")); if (numMsg > maxQueueDepth || numInvisible > maxQueueDepth) { if (sendDelay == 10) { sendDelay = 1000; logger.warn("event=slowing_send queue_depth=" + numMsg + " num_invisible=" + numInvisible); } } else { sendDelay = 10; } long end = System.currentTimeMillis(); attribSuccessCount.incrementAndGet(); logger.info("event=get_attributes rt="+(end-start)+" success_count=" + attribSuccessCount.get() + " failure_count=" + attribFailureCount.get() + " queue_depth=" + numMsg + " num_invisible=" + numInvisible); } catch (Exception ex) { attribFailureCount.incrementAndGet(); logger.error("event=get_attributes success_count=" + attribSuccessCount.get() + " failure_count=" + attribFailureCount.get(), ex); } } } } private static class MessageSender implements Runnable { @Override public void run() { Thread.currentThread().setName("MESSAGE_SENDER_" + rand.nextInt(100)); while (true) { try { Thread.currentThread().sleep(sendDelay); long start = System.currentTimeMillis(); String body = generateRandomMessage(20000); SendMessageRequest sendMessageRequest = new SendMessageRequest(queueUrl, body); SendMessageResult result = cqs1.sendMessage(sendMessageRequest); transactions.put(result.getMessageId(), System.currentTimeMillis()); long end = System.currentTimeMillis(); sendSuccessCount.incrementAndGet(); logger.info("event=message_sent rt="+(end-start)+" success_count=" + sendSuccessCount.get() + " failure_count=" + sendFailureCount.get()); } catch (Exception ex) { sendFailureCount.incrementAndGet(); logger.error("event=send_error success_count=" + sendSuccessCount.get() + " failure_count=" + sendFailureCount.get(), ex); } } } } private static class MessageReceiver implements Runnable { private void deleteMessage(String receiptHandle) { try { long start = System.currentTimeMillis(); DeleteMessageRequest deleteMessageRequest = new DeleteMessageRequest(); deleteMessageRequest.setQueueUrl(queueUrl); deleteMessageRequest.setReceiptHandle(receiptHandle); cqs1.deleteMessage(deleteMessageRequest); long end = System.currentTimeMillis(); deleteSuccessCount.incrementAndGet(); logger.info("event=delete rt="+(end-start)+" receipt_handle=" + receiptHandle + " success_count=" + deleteSuccessCount.get() + " failure_count=" + deleteFailureCount); } catch (Exception ex) { deleteFailureCount.incrementAndGet(); logger.error("event=send_error receipt_handle=" + receiptHandle + " success_count=" + deleteSuccessCount.get() + " failure_count=" + deleteFailureCount, ex); } } @Override public void run() { Thread.currentThread().setName("MESSAGE_RECEIVER_" + rand.nextInt(100)); while (true) { try { Thread.currentThread().sleep(receiveDelay); long start = System.currentTimeMillis(); ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(); receiveMessageRequest.setQueueUrl(queueUrl); receiveMessageRequest.setMaxNumberOfMessages(10); receiveMessageRequest.setWaitTimeSeconds(20); ReceiveMessageResult receiveMessageResult = cqs1.receiveMessage(receiveMessageRequest); long end = System.currentTimeMillis(); receiveSuccessCount.incrementAndGet(); actualMessagesReceivedCount.addAndGet(receiveMessageResult.getMessages().size()); if (receiveMessageResult.getMessages().size() > 0) { logger.info("event=messages_received rt="+(end-start)+" batch_count=" + receiveMessageResult.getMessages().size() + " success_count" + receiveSuccessCount.get() + " failure_count=" + receiveFailureCount.get() + " total_count=" + actualMessagesReceivedCount.get()); for (Message msg : receiveMessageResult.getMessages()) { Long ts = transactions.remove(msg.getMessageId()); if (ts != null) { long duration = System.currentTimeMillis()-ts; if (duration>maxInflightTime) { maxInflightTime = duration; } logger.info("num_msg_inflight=" + transactions.size() + " flight_time=" + duration + " max_flight_time=" + maxInflightTime); } deleteMessage(msg.getReceiptHandle()); } } else { logger.info("event=empty_receive rt="+(end-start)+" batch_count=" + receiveMessageResult.getMessages().size()); } } catch (Exception ex) { receiveFailureCount.incrementAndGet(); logger.error("event=send_error success_count" + receiveSuccessCount.get() + " failure_count=" + receiveFailureCount.get() + " total_count=" + actualMessagesReceivedCount.get(), ex); } } } } }