org.apache.aurora.scheduler.updater.InstanceActionHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.aurora.scheduler.updater.InstanceActionHandler.java

Source

/**
 * 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.updater;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Range;

import org.apache.aurora.common.quantity.Amount;
import org.apache.aurora.common.quantity.Time;
import org.apache.aurora.gen.JobUpdateStatus;
import org.apache.aurora.gen.ScheduleStatus;
import org.apache.aurora.scheduler.base.Query;
import org.apache.aurora.scheduler.base.Tasks;
import org.apache.aurora.scheduler.state.StateManager;
import org.apache.aurora.scheduler.storage.entities.IInstanceKey;
import org.apache.aurora.scheduler.storage.entities.IInstanceTaskConfig;
import org.apache.aurora.scheduler.storage.entities.IJobUpdateInstructions;
import org.apache.aurora.scheduler.storage.entities.IJobUpdateKey;
import org.apache.aurora.scheduler.storage.entities.IRange;
import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
import org.apache.aurora.scheduler.storage.entities.ITaskConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.aurora.gen.JobUpdateStatus.ROLLING_FORWARD;
import static org.apache.aurora.scheduler.storage.Storage.MutableStoreProvider;

interface InstanceActionHandler {

    Optional<Amount<Long, Time>> getReevaluationDelay(IInstanceKey instance, IJobUpdateInstructions instructions,
            MutableStoreProvider storeProvider, StateManager stateManager, UpdateAgentReserver reserver,
            JobUpdateStatus status, IJobUpdateKey key);

    Logger LOG = LoggerFactory.getLogger(InstanceActionHandler.class);

    static Optional<IScheduledTask> getExistingTask(MutableStoreProvider storeProvider, IInstanceKey instance) {

        return Optional.fromNullable(Iterables.getOnlyElement(
                storeProvider.getTaskStore().fetchTasks(Query.instanceScoped(instance).active()), null));
    }

    class AddTask implements InstanceActionHandler {
        private static ITaskConfig getTargetConfig(IJobUpdateInstructions instructions, boolean rollingForward,
                int instanceId) {

            if (rollingForward) {
                // Desired state is assumed to be non-null when AddTask is used.
                return instructions.getDesiredState().getTask();
            } else {
                for (IInstanceTaskConfig config : instructions.getInitialState()) {
                    for (IRange range : config.getInstances()) {
                        if (Range.closed(range.getFirst(), range.getLast()).contains(instanceId)) {
                            return config.getTask();
                        }
                    }
                }

                throw new IllegalStateException("Failed to find instance " + instanceId);
            }
        }

        @Override
        public Optional<Amount<Long, Time>> getReevaluationDelay(IInstanceKey instance,
                IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager,
                UpdateAgentReserver reserver, JobUpdateStatus status, IJobUpdateKey key) {

            Optional<IScheduledTask> task = getExistingTask(storeProvider, instance);
            if (task.isPresent()) {
                // Due to async event processing it's possible to have a race between task event
                // and instance addition. This is a perfectly valid case.
                LOG.info("Instance " + instance + " already exists while " + status);
            } else {
                LOG.info("Adding instance " + instance + " while " + status);
                ITaskConfig replacement = getTargetConfig(instructions, status == ROLLING_FORWARD,
                        instance.getInstanceId());
                stateManager.insertPendingTasks(storeProvider, replacement,
                        ImmutableSet.of(instance.getInstanceId()));
            }
            // A task state transition will trigger re-evaluation in this case, rather than a timer.
            return Optional.absent();
        }
    }

    class KillTask implements InstanceActionHandler {
        private final boolean reserveForReplacement;

        KillTask(boolean reserveForReplacement) {
            this.reserveForReplacement = reserveForReplacement;
        }

        @Override
        public Optional<Amount<Long, Time>> getReevaluationDelay(IInstanceKey instance,
                IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager,
                UpdateAgentReserver reserver, JobUpdateStatus status, IJobUpdateKey key) {

            Optional<IScheduledTask> task = getExistingTask(storeProvider, instance);
            if (task.isPresent()) {
                LOG.info("Killing " + instance + " while " + status);
                stateManager.changeState(storeProvider, Tasks.id(task.get()), Optional.absent(),
                        ScheduleStatus.KILLING, Optional.of("Killed for job update " + key.getId()));
                if (reserveForReplacement && task.get().getAssignedTask().isSetSlaveId()) {
                    reserver.reserve(task.get().getAssignedTask().getSlaveId(), instance);
                }
            } else {
                // Due to async event processing it's possible to have a race between task event
                // and it's deletion from the store. This is a perfectly valid case.
                LOG.info("No active instance " + instance + " to kill while " + status);
            }
            // A task state transition will trigger re-evaluation in this case, rather than a timer.
            return Optional.absent();
        }
    }

    class WatchRunningTask implements InstanceActionHandler {
        @Override
        public Optional<Amount<Long, Time>> getReevaluationDelay(IInstanceKey instance,
                IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager,
                UpdateAgentReserver reserver, JobUpdateStatus status, IJobUpdateKey key) {

            return Optional.of(Amount.of((long) instructions.getSettings().getMinWaitInInstanceRunningMs(),
                    Time.MILLISECONDS));
        }
    }
}