@Override public void start(final IJobUpdate update, final AuditData auditData) throws UpdateStateException { requireNonNull(update); requireNonNull(auditData); storage.write( (NoResult<UpdateStateException>) storeProvider -> { IJobUpdateSummary summary = update.getSummary(); IJobUpdateInstructions instructions = update.getInstructions(); IJobKey job = summary.getKey().getJob(); // Validate the update configuration by making sure we can create an updater for it. updateFactory.newUpdate(update.getInstructions(), true); if (instructions.getInitialState().isEmpty() && !instructions.isSetDesiredState()) { throw new IllegalArgumentException("Update instruction is a no-op."); } List<IJobUpdateSummary> activeJobUpdates = storeProvider.getJobUpdateStore().fetchJobUpdateSummaries(queryActiveByJob(job)); if (!activeJobUpdates.isEmpty()) { throw new UpdateStateException( "An active update already exists for this job, " + "please terminate it before starting another. " + "Active updates are those in states " + Updates.ACTIVE_JOB_UPDATE_STATES); } LOG.info("Starting update for job " + job); ILock lock; try { lock = lockManager.acquireLock( ILockKey.build(LockKey.job(job.newBuilder())), auditData.getUser()); } catch (LockException e) { throw new UpdateStateException(e.getMessage(), e); } storeProvider .getJobUpdateStore() .saveJobUpdate(update, Optional.of(requireNonNull(lock.getToken()))); JobUpdateStatus status = ROLLING_FORWARD; if (isCoordinatedUpdate(instructions)) { status = ROLL_FORWARD_AWAITING_PULSE; pulseHandler.initializePulseState(update, status); } recordAndChangeJobUpdateStatus( storeProvider, summary.getKey(), addAuditData(newEvent(status), auditData)); }); }
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 Amount<Long, Time> getReevaluationDelay( IInstanceKey instance, IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager, JobUpdateStatus status) { return Amount.of( (long) instructions.getSettings().getMinWaitInInstanceRunningMs(), Time.MILLISECONDS); }
@Override public Amount<Long, Time> getReevaluationDelay( IInstanceKey instance, IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager, JobUpdateStatus status) { LOG.info("Adding instance " + instance + " while " + status); ITaskConfig replacement = getTargetConfig(instructions, status == ROLLING_FORWARD, instance.getInstanceId()); stateManager.insertPendingTasks( storeProvider, replacement, ImmutableSet.of(instance.getInstanceId())); return Amount.of( (long) instructions.getSettings().getMaxWaitToInstanceRunningMs(), Time.MILLISECONDS); }
@Override public Amount<Long, Time> getReevaluationDelay( IInstanceKey instance, IJobUpdateInstructions instructions, MutableStoreProvider storeProvider, StateManager stateManager, JobUpdateStatus status) { String taskId = Tasks.id( Iterables.getOnlyElement( storeProvider .getTaskStore() .fetchTasks(Query.instanceScoped(instance).active()))); LOG.info("Killing " + instance + " while " + status); stateManager.changeState( storeProvider, taskId, Optional.absent(), ScheduleStatus.KILLING, Optional.of("Killed for job update.")); return Amount.of( (long) instructions.getSettings().getMaxWaitToInstanceRunningMs(), Time.MILLISECONDS); }
private static boolean isCoordinatedUpdate(IJobUpdateInstructions instructions) { return instructions.getSettings().getBlockIfNoPulsesAfterMs() > 0; }