@Override public Boolean isHostLocal() { return BootstrapArgs.isCloudController(); }
@Override public void fireEvent(final Hertz event) { final long defaultPollIntervalSeconds = TimeUnit.MINUTES.toSeconds(DEFAULT_POLL_INTERVAL_MINS); if (!Bootstrap.isOperational() || !BootstrapArgs.isCloudController() || !event.isAsserted(defaultPollIntervalSeconds)) { return; } else { if (DEFAULT_POLL_INTERVAL_MINS >= 1) { COLLECTION_INTERVAL_TIME_MS = ((int) TimeUnit.MINUTES.toMillis(DEFAULT_POLL_INTERVAL_MINS) / 2); } else { COLLECTION_INTERVAL_TIME_MS = 0; } if (COLLECTION_INTERVAL_TIME_MS == 0 || HISTORY_SIZE > 15 || HISTORY_SIZE < 1) { LOG.debug("The instance usage report is disabled"); } else if (COLLECTION_INTERVAL_TIME_MS <= MAX_WRITE_INTERVAL_MS) { try { if (event.isAsserted(defaultPollIntervalSeconds)) { if (Bootstrap.isFinished() && Hosts.isCoordinator()) { CloudWatchHelper.DefaultInstanceInfoProvider.refresh(); for (final ServiceConfiguration ccConfig : Topology.enabledServices(ClusterController.class)) { final String ccHost = ccConfig.getHostName(); if (busyHosts.replace(ccHost, false, true) || busyHosts.putIfAbsent(ccHost, true) == null) { Threads.lookup(Reporting.class, DescribeSensorsListener.class) .submit( new Callable<Object>() { @Override public Object call() throws Exception { final ExecutorService executorService = Threads.lookup( Reporting.class, DescribeSensorsListener.class, "response-processing") .limitTo(4); final long startTime = System.currentTimeMillis(); try { final List<String> allInstanceIds = VmInstances.listWithProjection( VmInstances.instanceIdProjection(), VmInstance.criterion(VmState.RUNNING), VmInstance.zoneCriterion(ccConfig.getPartition()), VmInstance.nonNullNodeCriterion()); final Iterable<List<String>> processInts = Iterables.partition(allInstanceIds, SENSOR_QUERY_BATCH_SIZE); for (final List<String> instIds : processInts) { final ArrayList<String> instanceIds = Lists.newArrayList(instIds); /** * Here this is hijacking the sensor callback in order to control * the thread of execution used when firing */ final DescribeSensorCallback msgCallback = new DescribeSensorCallback( HISTORY_SIZE, COLLECTION_INTERVAL_TIME_MS, instanceIds) { @Override public void fireException(Throwable e) {} @Override public void fire(DescribeSensorsResponse msg) {} }; /** * Here we actually get the future reference to the result and on * a response processing thread, invoke .fire(). */ final DescribeSensorsResponse response = AsyncRequests.newRequest(msgCallback) .dispatch(ccConfig) .get(); executorService.submit( new Runnable() { @Override public void run() { try { new DescribeSensorCallback( HISTORY_SIZE, COLLECTION_INTERVAL_TIME_MS, instanceIds) .fire(response); } catch (Exception e) { Exceptions.maybeInterrupted(e); } } }); } } finally { /** Only and finally set the busy bit back to false. */ busyHosts.put(ccHost, false); LOG.debug( "Sensor polling for " + ccHost + " took " + (System.currentTimeMillis() - startTime) + "ms"); } return null; } }); } else { LOG.warn( "Skipping sensors polling for " + ccHost + ", previous poll not complete."); } } } } } catch (Exception ex) { LOG.error("Unable to listen for describe sensors events", ex); } } else { LOG.error( "DEFAULT_POLL_INTERVAL_MINS : " + DEFAULT_POLL_INTERVAL_MINS + " must be less than 1440 minutes"); } } }