All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hubspot.singularity.scheduler.SingularitySchedulerPoller Maven / Gradle / Ivy

package com.hubspot.singularity.scheduler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.inject.Singleton;

import org.apache.mesos.v1.Protos.Offer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.hubspot.singularity.SingularityAction;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.DisasterManager;
import com.hubspot.singularity.mesos.OfferCache;
import com.hubspot.singularity.mesos.SingularityMesosOfferScheduler;
import com.hubspot.singularity.mesos.SingularityMesosSchedulerClient;
import com.hubspot.singularity.mesos.SingularityOfferCache.CachedOffer;
import com.hubspot.singularity.mesos.SingularityOfferHolder;
import com.hubspot.singularity.mesos.SingularitySchedulerLock;

@Singleton
public class SingularitySchedulerPoller extends SingularityLeaderOnlyPoller {

  private static final Logger LOG = LoggerFactory.getLogger(SingularitySchedulerPoller.class);

  private final OfferCache offerCache;
  private final SingularityMesosSchedulerClient schedulerClient;
  private final SingularityMesosOfferScheduler offerScheduler;
  private final DisasterManager disasterManager;
  private final SingularitySchedulerLock lock;

  @Inject
  SingularitySchedulerPoller(SingularityMesosOfferScheduler offerScheduler, OfferCache offerCache, SingularityMesosSchedulerClient schedulerClient,
                             SingularityConfiguration configuration, SingularitySchedulerLock lock, DisasterManager disasterManager) {
    super(configuration.getCheckSchedulerEverySeconds(), TimeUnit.SECONDS, true);

    this.offerCache = offerCache;
    this.offerScheduler = offerScheduler;
    this.schedulerClient = schedulerClient;
    this.disasterManager = disasterManager;
    this.lock = lock;
  }

  @Override
  public void runActionOnPoll() {
    if (disasterManager.isDisabled(SingularityAction.RUN_SCHEDULER_POLLER)) {
      LOG.warn("Scheduler poller is disabled");
      return;
    }


    lock.runWithOffersLock(() -> {
      List cachedOffers = offerCache.checkoutOffers();
      Map offerIdToCachedOffer = new HashMap<>(cachedOffers.size());
      List offers = new ArrayList<>(cachedOffers.size());

      for (CachedOffer cachedOffer : cachedOffers) {
        offerIdToCachedOffer.put(cachedOffer.getOfferId(), cachedOffer);
        offers.add(cachedOffer.getOffer());
      }

      Collection offerHolders = offerScheduler.checkOffers(offers);

      if (offerHolders.isEmpty()) {
        return;
      }

      int acceptedOffers = 0;
      int launchedTasks = 0;

      for (SingularityOfferHolder offerHolder : offerHolders) {
        List cachedOffersFromHolder = offerHolder.getOffers().stream().map((o) -> offerIdToCachedOffer.get(o.getId().getValue())).collect(Collectors.toList());

        if (!offerHolder.getAcceptedTasks().isEmpty()) {
          List unusedOffers = offerHolder.launchTasksAndGetUnusedOffers(schedulerClient);
          launchedTasks += offerHolder.getAcceptedTasks().size();
          acceptedOffers += cachedOffersFromHolder.size() - unusedOffers.size();

          // Return to the cache those offers which we checked out of the cache, but didn't end up using.
          List unusedCachedOffers = unusedOffers.stream().map((o) -> offerIdToCachedOffer.get(o.getId().getValue())).collect(Collectors.toList());
          unusedCachedOffers.forEach((cachedOffer) -> {
            offerIdToCachedOffer.remove(cachedOffer.getOfferId());
            offerCache.returnOffer(cachedOffer);
          });

          // Notify the cache of the cached offers that we did use.
          cachedOffersFromHolder.removeAll(unusedCachedOffers);
          cachedOffersFromHolder.forEach((cachedOffer) -> {
            offerIdToCachedOffer.remove(cachedOffer.getOfferId());
            offerCache.useOffer(cachedOffer);
          });
        } else {
          cachedOffersFromHolder.forEach((cachedOffer) -> {
            offerIdToCachedOffer.remove(cachedOffer.getOfferId());
            offerCache.returnOffer(cachedOffer);
          });
        }
      }

      LOG.info("{} remaining offers not accounted for in offer check", offerIdToCachedOffer.size());
      offerIdToCachedOffer.values().forEach(offerCache::returnOffer);

      LOG.info("Launched {} tasks on {} cached offers (returned {})", launchedTasks, acceptedOffers, offerHolders.size() - acceptedOffers);
    }, getClass().getSimpleName());
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy