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

com.elastisys.scale.cloudpool.commons.scaledown.TerminationScheduler Maven / Gradle / Ivy

package com.elastisys.scale.cloudpool.commons.scaledown;

import static com.elastisys.scale.cloudpool.api.types.Machine.remainingInstanceHourTime;
import static com.google.common.base.Preconditions.checkArgument;

import java.util.List;

import org.joda.time.DateTime;

import com.elastisys.scale.cloudpool.api.types.Machine;
import com.elastisys.scale.cloudpool.commons.termqueue.ScheduledTermination;
import com.elastisys.scale.commons.util.time.UtcTime;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

/**
 * Schedules termination of machine instances so that machine instances are
 * terminated as close as possible to the end of the current instance hour (with
 * a certain safety margin so that termination has time to complete).
 *
 *
 */
public class TerminationScheduler {

	/**
	 * How many seconds prior to the next instance hour machine instances are to
	 * be scheduled for termination. This should be set to a conservative and
	 * safe value to prevent machines from being billed for an additional hour.
	 * A value of zero is used to specify immediate termination when a
	 * scale-down is ordered.
	 */
	private final long instanceHourMargin;

	/**
	 * Constructs a new {@link TerminationScheduler}.
	 *
	 * @param instanceHourMargin
	 *            How many seconds prior to the next instance hour machine
	 *            instances are to be scheduled for termination. This should be
	 *            set to a conservative and safe value to prevent machines from
	 *            being billed for an additional hour. A value of zero is used
	 *            to specify immediate termination when a scale-down is ordered.
	 */
	public TerminationScheduler(long instanceHourMargin) {
		checkArgument(instanceHourMargin < 3600,
				"instanceHourMargin must be smaller than 3600 seconds");
		this.instanceHourMargin = instanceHourMargin;
	}

	/**
	 * Schedules termination for a number of machine instances.
	 *
	 * @param victims
	 *            The machine instances to be scheduled for termination.
	 * @return A list of {@link ScheduledTermination}s, one for each victim.
	 */
	public List scheduleEvictions(List victims) {
		Preconditions.checkNotNull(victims, "null victims");
		List evictions = Lists.newArrayList();
		for (Machine victim : victims) {
			evictions.add(scheduleEviction(victim));
		}
		return evictions;
	}

	/**
	 * Schedules termination for a single machine instance.
	 *
	 * @param victim
	 *            The machine instance to be scheduled for termination.
	 * @return A list of {@link ScheduledTermination}s, one for each victim.
	 */
	public ScheduledTermination scheduleEviction(Machine victim) {
		Preconditions.checkNotNull(victim, "null victim");
		Preconditions.checkNotNull(victim.getLaunchTime(),
				"cannot schedule termination for a "
						+ "machine instance without launch time");

		DateTime terminationTime = calculateTerminationTime(victim,
				this.instanceHourMargin);
		return new ScheduledTermination(victim, terminationTime);
	}

	private DateTime calculateTerminationTime(Machine victim,
			long instanceHourMargin) {
		if (instanceHourMargin <= 0) {
			// non-positive margin implies immediate termination
			return UtcTime.now();
		}

		long secondsLeftOfInstanceHour = remainingInstanceHourTime().apply(
				victim);
		long secondsLeftOfInstanceHourWithMargin = secondsLeftOfInstanceHour
				- instanceHourMargin;
		// if time left of billing hour is less than margin, we terminate
		// immediately
		secondsLeftOfInstanceHourWithMargin = Math.max(
				secondsLeftOfInstanceHourWithMargin, 0);
		DateTime terminationTime = UtcTime.now().plusSeconds(
				(int) secondsLeftOfInstanceHourWithMargin);
		return terminationTime;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy