Package com.comcast.cns.tools

Source Code of com.comcast.cns.tools.CNSEndpointPublisherJobProducer

/**
* 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.cns.tools;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.Logger;

import com.comcast.cmb.common.controller.CMBControllerServlet;
import com.comcast.cmb.common.persistence.PersistenceFactory;
import com.comcast.cmb.common.persistence.AbstractDurablePersistence.CMB_SERIALIZER;
import com.comcast.cmb.common.util.CMBProperties;
import com.comcast.cmb.common.util.PersistenceException;
import com.comcast.cmb.common.util.ValueAccumulator.AccumulatorName;
import com.comcast.cns.model.CNSEndpointPublishJob;
import com.comcast.cns.model.CNSMessage;
import com.comcast.cns.model.CNSSubscription;
import com.comcast.cns.model.CNSEndpointPublishJob.CNSEndpointSubscriptionInfo;
import com.comcast.cns.persistence.CNSCachedEndpointPublishJob;
import com.comcast.cns.persistence.ICNSSubscriptionPersistence;
import com.comcast.cns.persistence.TopicNotFoundException;
import com.comcast.cqs.model.CQSMessage;

/**
* This class represents the Producer that reads the CNSMessage, partitions the subscribers and
* creates the EndpointPublishJobs
* @author aseem, bwolf, ppang
*
* Class is thread-safe
*/

public class CNSEndpointPublisherJobProducer implements CNSPublisherPartitionRunnable {
 
    private static Logger logger = Logger.getLogger(CNSEndpointPublisherJobProducer.class);
   
    private static final String CNS_PRODUCER_QUEUE_NAME_PREFIX = CMBProperties.getInstance().getCNSPublishQueueNamePrefix();
   
    private static volatile boolean initialized = false;
   
    private static volatile ICNSSubscriptionPersistence subscriptionPersistence = PersistenceFactory.getSubscriptionPersistence();

    private long processingDelayMillis = 10;

   /*
    * Read the EndpointPublishQ_<m> property and ensuring they exist (create if not)
    * @throws PersistenceException
    */
   public static void initialize() throws PersistenceException {
     if (initialized) {
       return;
     }
     logger.info("event=initializing_cns_producer");
     initialized = true;
   }

   public static void shutdown() {
       initialized = false;
       logger.info("event=shutdown_cns_producer");
   }
  
    @Override
    /**
     * 1. Call ReceiveMessage(PublishJobQ.<n> where n  in [0..numPublishJobQs]
     * 2. if no message, go to sleep for 100ms and go back to 1
     * 3. if message found,
     *  3.1 read sub-list for topic,
     *  3.2 partition them by batch size
     *  3.3 Enqueue into EndpointPublishJobQ.<m> where m is randomly selected between [0..numEPPublishJobQs]
     *  3.4 go back to 1
     */   
    public boolean run (int partition) {
     
        boolean messageFound = false;
       
        if (!initialized) {
            throw new IllegalStateException("Not initialized");
        }
       
        long ts1 = System.currentTimeMillis();
      CMBControllerServlet.valueAccumulator.initializeAllCounters();
     
      try {

            if (CNSPublisher.lastProducerMinute.getAndSet(ts1/(1000*60)) != ts1/(1000*60)) {
               
            String hostAddress = InetAddress.getLocalHost().getHostAddress();
                logger.info("event=ping version=" + CMBControllerServlet.VERSION + " ip=" + hostAddress);

            try {
              Map<String, String> values = new HashMap<String, String>();
              values.put("producerTimestamp", System.currentTimeMillis() + "");
              values.put("jmxport", System.getProperty("com.sun.management.jmxremote.port", "0"));
              values.put("mode", CNSPublisher.getModeString());
              values.put("dataCenter", CMBProperties.getInstance().getCMBDataCenter());
                  CNSPublisher.cassandraHandler.insertRow(CMBProperties.getInstance().getCNSKeyspace(), hostAddress, "CNSWorkers", values, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER, CMB_SERIALIZER.STRING_SERIALIZER, null);
              } catch (Exception ex) {
              logger.warn("event=ping_glitch", ex);
            }
            }
         
          String publishJobQName = CNS_PRODUCER_QUEUE_NAME_PREFIX + partition;
          String queueUrl = CQSHandler.getRelativeCnsInternalQueueUrl(publishJobQName);
         
          CQSMessage msg = null;
          int waitTimeSecs = 0;
         
          if (CMBProperties.getInstance().isCQSLongPollEnabled()) {
            waitTimeSecs = CMBProperties.getInstance().getCMBRequestTimeoutSec();
          }

          List<CQSMessage> l = CQSHandler.receiveMessage(queueUrl, waitTimeSecs, 1);

          if (l.size() > 0) {
            msg = l.get(0);
          }

          CNSWorkerMonitor.getInstance().registerCQSServiceAvailable(true);

          if (msg != null) {
           
            // if long polling disabled and message found reset exponential backoff
           
            if (!CMBProperties.getInstance().isCQSLongPollEnabled()) {
              processingDelayMillis = 10;
            }
           
              CNSMessage publishMessage = CNSMessage.parseInstance(msg.getBody());
             
              int messageExpirationSeconds = CMBProperties.getInstance().getCNSMessageExpirationSeconds();
             
              if (messageExpirationSeconds != 0 && System.currentTimeMillis() - publishMessage.getTimestamp().getTime() > messageExpirationSeconds*1000) {
                  logger.error("event=deleting_publish_job reason=message_too_old topic_arn=" + publishMessage.getTopicArn());
                  CQSHandler.deleteMessage(queueUrl, msg.getReceiptHandle());
                  CMBControllerServlet.valueAccumulator.deleteAllCounters();
                  return true; // return true to avoid backoff
              }
             
              List<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo> subscriptions = null;
              long t1=System.currentTimeMillis();
              try {
                  subscriptions = getSubscriptionsForTopic(publishMessage.getTopicArn());
              } catch (TopicNotFoundException e) {

                //delete this message/job since the topic was deleted.
                 
                logger.error("event=deleting_publish_job reason=topic_not_found topic_arn=" + publishMessage.getTopicArn());
                  CQSHandler.deleteMessage(queueUrl, msg.getReceiptHandle());
                  CMBControllerServlet.valueAccumulator.deleteAllCounters();
                  return true; // return true to avoid backoff
             
              } catch (Exception ex) {
                  logger.error("event=skipping_publish_job reason=error_fetching_subscriptions", ex);
                  CMBControllerServlet.valueAccumulator.deleteAllCounters();
                  return true; // return true to avoid backoff
              }
              logger.debug("event=get_subscription_list ms="+(System.currentTimeMillis()-t1));
              if (subscriptions != null && subscriptions.size() > 0) {
               
                  messageFound = true;
                  List<CNSEndpointPublishJob> epPublishJobs = createEndpointPublishJobs(publishMessage, subscriptions);
                 
                  for (CNSEndpointPublishJob epPublishJob: epPublishJobs) {
                   
                    String epQueueName =  CMBProperties.getInstance().getCNSEndpointPublishQueueNamePrefix() + ((new Random()).nextInt(CMBProperties.getInstance().getCNSNumEndpointPublishJobQueues()));
                      String epQueueUrl = CQSHandler.getRelativeCnsInternalQueueUrl(epQueueName);
                      CQSHandler.sendMessage(epQueueUrl, epPublishJob.serialize());
                  }
              }
             
              CQSHandler.deleteMessage(queueUrl, msg.getReceiptHandle());
             
              long ts2 = System.currentTimeMillis();
              logger.debug("event=processed_producer_job cns_cqs_ms=" + CMBControllerServlet.valueAccumulator.getCounter(AccumulatorName.CNSCQSTime) + " resp_ms=" + (ts2 - ts1));

          } else {
           
            // if long polling disabled and no message found do exponential backoff
           
            if (!CMBProperties.getInstance().isCQSLongPollEnabled()) {
             
              if (processingDelayMillis < CMBProperties.getInstance().getCNSProducerProcessingMaxDelay()) {
                processingDelayMillis *= 2;
              }
             
              Thread.sleep(processingDelayMillis);
            }
           
          }
     
      } catch (Exception ex) {
        logger.error("event=job_producer_failure", ex);
        CQSHandler.ensureQueuesExist(CNS_PRODUCER_QUEUE_NAME_PREFIX, CMBProperties.getInstance().getCNSNumPublishJobQueues());
      }

      CMBControllerServlet.valueAccumulator.deleteAllCounters();
     
      return messageFound;
    }
   
   
    public static List<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo> getSubscriptionsForTopic(String topicArn) throws Exception {       
     
      List<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo> subInfoList = new ArrayList<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo>();
     
      if (CMBProperties.getInstance().isCNSUseSubInfoCache()) {
          subInfoList.addAll(CNSCachedEndpointPublishJob.getSubInfos(topicArn));
      } else {
     
        String nextToken = null;
         
        while (true) {
         
          List<CNSSubscription> subscriptions = subscriptionPersistence.listSubscriptionsByTopic(nextToken, topicArn, null, 1000);
             
          if (subscriptions == null || subscriptions.size() == 0) {
                  break;
              }
             
          boolean allPendingConfirmation = true;
             
          for (CNSSubscription subscription: subscriptions) {
             
            if (!subscription.getArn().equals("PendingConfirmation")) {
                      allPendingConfirmation = false;
                      subInfoList.add(new CNSEndpointPublishJob.CNSEndpointSubscriptionInfo(subscription.getProtocol(), subscription.getEndpoint(), subscription.getArn(), subscription.getRawMessageDelivery()));
                      nextToken = subscription.getArn();
                  }
              }
         
              if (allPendingConfirmation) {
                  break;
              }
          }
      }
     
      return subInfoList;
    }
   
    public static List<CNSEndpointPublishJob> createEndpointPublishJobs(CNSMessage message, List<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo> subscriptions) {

      List<CNSEndpointPublishJob> epPublishJobs = new ArrayList<CNSEndpointPublishJob>();
     
      if (subscriptions != null) {
     
        int maxSubsPerEPPublishJob = CMBProperties.getInstance().getCNSMaxSubscriptionsPerEndpointPublishJob();
        int numEPPublishJobs = (int)Math.ceil(subscriptions.size()/(float)maxSubsPerEPPublishJob);
        int subIndex = 0;
       
        for (int i=0; i<numEPPublishJobs; i++) {
         
          List<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo> epPublishJobSubscriptions = new ArrayList<CNSEndpointPublishJob.CNSEndpointSubscriptionInfo>();
         
          for (int j=0; j<maxSubsPerEPPublishJob; j++) {
             
            CNSEndpointSubscriptionInfo subInfo;
             
            if (CMBProperties.getInstance().isCNSUseSubInfoCache()) {
                  subInfo = new CNSCachedEndpointPublishJob.CNSCachedEndpointSubscriptionInfo(subscriptions.get(subIndex).protocol, subscriptions.get(subIndex).endpoint, subscriptions.get(subIndex).subArn, subscriptions.get(subIndex).rawDelivery);
              } else {
                  subInfo = new CNSEndpointSubscriptionInfo(subscriptions.get(subIndex).protocol, subscriptions.get(subIndex).endpoint, subscriptions.get(subIndex).subArn, subscriptions.get(subIndex).rawDelivery);
              }
              
            epPublishJobSubscriptions.add(subInfo);
           
            if (++subIndex==subscriptions.size()) {
              break;
            }
          }
         
          CNSEndpointPublishJob job;
         
          if (CMBProperties.getInstance().isCNSUseSubInfoCache()) {
              job = new CNSCachedEndpointPublishJob(message, epPublishJobSubscriptions);
          } else {
              job = new CNSEndpointPublishJob(message, epPublishJobSubscriptions);
          }
         
          epPublishJobs.add(job);
        }
      }
       
      return epPublishJobs;
    }
}
TOP

Related Classes of com.comcast.cns.tools.CNSEndpointPublisherJobProducer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.