package org.openstack.atlas.usage.jobs; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openstack.atlas.jobs.AbstractJob; import org.openstack.atlas.restclients.atomhopper.AtomHopperClient; import org.openstack.atlas.restclients.atomhopper.AtomHopperClientImpl; import org.openstack.atlas.restclients.atomhopper.config.AtomHopperConfiguration; import org.openstack.atlas.restclients.atomhopper.util.AtomHopperUtil; import org.openstack.atlas.restclients.auth.IdentityAuthClient; import org.openstack.atlas.restclients.auth.IdentityClientImpl; import org.openstack.atlas.service.domain.entities.JobName; import org.openstack.atlas.service.domain.entities.Usage; import org.openstack.atlas.service.domain.events.repository.LoadBalancerEventRepository; import org.openstack.atlas.service.domain.repository.LoadBalancerRepository; import org.openstack.atlas.service.domain.repository.UsageRepository; import org.openstack.atlas.usage.BatchAction; import org.openstack.atlas.usage.ExecutionUtilities; import org.openstack.atlas.usage.thread.UsageThread; import org.openstack.atlas.usage.thread.service.RejectedExecutionHandler; import org.openstack.atlas.usage.thread.service.ThreadPoolExecutorService; import org.openstack.atlas.usage.thread.service.ThreadPoolMonitorService; import org.openstack.atlas.usage.thread.util.ThreadServiceUtil; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; import static org.openstack.atlas.restclients.atomhopper.config.AtomHopperConfigurationKeys.*; @Component public class AtomHopperUsagePusher extends AbstractJob { private final Log LOG = LogFactory.getLog(AtomHopperUsagePusher.class); private final static int QUERY_SIZE = 1000; private int NUM_ATTEMPTS; private int BATCH_SIZE; private boolean pushUsage; private boolean pushFailedUsage; private long keepAliveTime; private int corePoolSize; private int maxPoolSize; private ThreadPoolExecutor poolExecutor; private AtomHopperClient ahuslClient; private IdentityAuthClient identityClient; @Autowired private LoadBalancerRepository loadBalancerRepository; @Autowired private LoadBalancerEventRepository loadBalancerEventRepository; @Autowired private UsageRepository usageRepository; @Autowired private ThreadPoolMonitorService threadPoolMonitorService; @Autowired private ThreadPoolExecutorService threadPoolExecutorService; @Override public Log getLogger() { return LOG; } @Override public JobName getJobName() { return JobName.ATOM_LOADBALANCER_USAGE_POLLER; } @Override public void setup(JobExecutionContext jobExecutionContext) throws JobExecutionException { AtomHopperConfiguration configuration = new AtomHopperConfiguration(); NUM_ATTEMPTS = Integer.valueOf(configuration.getString(ahusl_num_attempts)); BATCH_SIZE = Integer.valueOf(configuration.getString(ahusl_pool_task_count)); pushUsage = Boolean.valueOf(configuration.getString(allow_ahusl)); pushFailedUsage = Boolean.valueOf(configuration.getString(ahusl_run_failed_entries)); maxPoolSize = Integer.valueOf(configuration.getString(ahusl_pool_max_size)); corePoolSize = Integer.valueOf(configuration.getString(ahusl_pool_core_size)); keepAliveTime = Long.valueOf(configuration.getString(ahusl_pool_conn_timeout)); try { poolExecutor = threadPoolExecutorService.createNewThreadPool(corePoolSize, maxPoolSize, keepAliveTime, QUERY_SIZE, new RejectedExecutionHandler()); ThreadServiceUtil.startThreadMonitor(poolExecutor, threadPoolMonitorService); LOG.debug("Setting up the ahuslClient..."); ahuslClient = new AtomHopperClientImpl(); identityClient = new IdentityClientImpl(); } catch (Exception e) { System.out.printf("Exception: %s\n", AtomHopperUtil.getExtendedStackTrace(e)); LOG.error(String.format("Exception: %s\n", AtomHopperUtil.getExtendedStackTrace(e))); throw new JobExecutionException(e); } } @Override public void run() throws Exception { if (pushUsage) { pushUsage(); } if (pushFailedUsage) { pushFailedUsage(); } } @Override public void cleanup() { ThreadServiceUtil.shutDownAHUSLServices(poolExecutor, threadPoolMonitorService, ahuslClient); } private void pushUsage() throws Exception { final List<Usage> allUsages = loadBalancerRepository.getUsageNeedsPushed(AtomHopperUtil.getStartCal(), AtomHopperUtil.getNow(), NUM_ATTEMPTS); LOG.info(String.format("Pushing %d records marked for push", allUsages.size())); push(allUsages); } private void pushFailedUsage() throws Exception { final List<Usage> allUsages = loadBalancerRepository.getUsageRetryNeedsPushed(AtomHopperUtil.getStartCal(), AtomHopperUtil.getNow(), NUM_ATTEMPTS); LOG.info(String.format("Pushing %d records marked for retry", allUsages.size())); push(allUsages); } private void push(List<Usage> allUsages) throws Exception { if (!allUsages.isEmpty()) { sortUsages(allUsages); BatchAction<Usage> batchAction = new BatchAction<Usage>() { public void execute(Collection<Usage> allUsages) throws Exception { poolExecutor.execute(new UsageThread(allUsages, ahuslClient, identityClient, usageRepository, loadBalancerEventRepository, alertRepository)); } }; ExecutionUtilities.ExecuteInBatches(allUsages, BATCH_SIZE, batchAction); } else { LOG.debug("No usages to push to ATOM Hopper at this time."); } } private void sortUsages(List<Usage> usages) { Collections.sort(usages, new Comparator<Usage>() { public int compare(Usage usage1, Usage usage2) { return usage1.getId().compareTo(usage2.getId()); } }); } }