/** * 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 org.apache.aurora.scheduler.offers; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; import javax.inject.Singleton; import com.google.inject.AbstractModule; import com.google.inject.PrivateModule; import com.google.inject.TypeLiteral; import org.apache.aurora.common.args.Arg; import org.apache.aurora.common.args.CmdLine; import org.apache.aurora.common.args.constraints.NotNegative; import org.apache.aurora.common.quantity.Amount; import org.apache.aurora.common.quantity.Time; import org.apache.aurora.common.util.Random; import org.apache.aurora.scheduler.events.PubsubEventModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Binding module for resource offer management. */ public class OffersModule extends AbstractModule { private static final Logger LOG = LoggerFactory.getLogger(OffersModule.class); @CmdLine(name = "min_offer_hold_time", help = "Minimum amount of time to hold a resource offer before declining.") @NotNegative private static final Arg<Amount<Integer, Time>> MIN_OFFER_HOLD_TIME = Arg.create(Amount.of(5, Time.MINUTES)); @CmdLine(name = "offer_hold_jitter_window", help = "Maximum amount of random jitter to add to the offer hold time window.") @NotNegative private static final Arg<Amount<Integer, Time>> OFFER_HOLD_JITTER_WINDOW = Arg.create(Amount.of(1, Time.MINUTES)); @CmdLine(name = "offer_filter_duration", help = "Duration after which we expect Mesos to re-offer unused resources. A short duration " + "improves scheduling performance in smaller clusters, but might lead to resource " + "starvation for other frameworks if you run many frameworks in your cluster.") private static final Arg<Amount<Long, Time>> OFFER_FILTER_DURATION = Arg.create(Amount.of(5L, Time.SECONDS)); @CmdLine(name = "unavailability_threshold", help = "Threshold time, when running tasks should be drained from a host, before a host " + "becomes unavailable. Should be greater than min_offer_hold_time + " + "offer_hold_jitter_window.") private static final Arg<Amount<Long, Time>> UNAVAILABILITY_THRESHOLD = Arg.create(Amount.of(6L, Time.MINUTES)); /** * Binding annotation for the threshold to veto tasks with unavailability. */ @Qualifier @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) public @interface UnavailabilityThreshold { } @Override protected void configure() { long offerHoldTime = OFFER_HOLD_JITTER_WINDOW.get().as(Time.SECONDS) + MIN_OFFER_HOLD_TIME.get().as(Time.SECONDS); if (UNAVAILABILITY_THRESHOLD.get().as(Time.SECONDS) < offerHoldTime) { LOG.warn("unavailability_threshold ({}) is less than the sum of min_offer_hold_time ({}) and" + "offer_hold_jitter_window ({}). This creates risks of races between launching and" + "draining", UNAVAILABILITY_THRESHOLD.get(), MIN_OFFER_HOLD_TIME.get(), OFFER_HOLD_JITTER_WINDOW.get()); } bind(new TypeLiteral<Amount<Long, Time>>() { }) .annotatedWith(UnavailabilityThreshold.class) .toInstance(UNAVAILABILITY_THRESHOLD.get()); install(new PrivateModule() { @Override protected void configure() { bind(OfferSettings.class).toInstance( new OfferSettings( OFFER_FILTER_DURATION.get(), new RandomJitterReturnDelay( MIN_OFFER_HOLD_TIME.get().as(Time.MILLISECONDS), OFFER_HOLD_JITTER_WINDOW.get().as(Time.MILLISECONDS), Random.Util.newDefaultRandom()))); bind(OfferManager.class).to(OfferManager.OfferManagerImpl.class); bind(OfferManager.OfferManagerImpl.class).in(Singleton.class); expose(OfferManager.class); expose(OfferSettings.class); } }); PubsubEventModule.bindSubscriber(binder(), OfferManager.class); } }