use of com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt in project titus-control-plane by Netflix.
the class KillInitiatedActions method createShrinkAction.
private static TitusModelAction createShrinkAction(TitusChangeAction.Builder changeActionBuilder, VersionSupplier versionSupplier) {
return TitusModelAction.newModelUpdate(changeActionBuilder).summary("Shrinking job as a result of terminate and shrink request").jobUpdate(jobHolder -> {
Job<ServiceJobExt> serviceJob = jobHolder.getEntity();
ServiceJobExt oldExt = serviceJob.getJobDescriptor().getExtensions();
Capacity oldCapacity = oldExt.getCapacity();
// A job of size 0 may still have some tasks running just after job scale-down request.
// We must make sure that we do not decrement the job size if it is already 0.
int newDesired = Math.max(0, oldCapacity.getDesired() - 1);
Capacity newCapacity = oldCapacity.toBuilder().withMin(Math.min(oldCapacity.getMin(), newDesired)).withDesired(newDesired).build();
Job<ServiceJobExt> newJob = serviceJob.toBuilder().withJobDescriptor(serviceJob.getJobDescriptor().toBuilder().withExtensions(oldExt.toBuilder().withCapacity(newCapacity).build()).build()).build();
newJob = VersionSuppliers.nextVersion(newJob, versionSupplier);
return jobHolder.setEntity(newJob);
});
}
use of com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt in project titus-control-plane by Netflix.
the class KillInitiatedActions method userInitiateTaskKillAction.
/**
* Change a task to {@link TaskState#KillInitiated} state, store it, and send the kill command to the compute provider.
* All models are updated when both operations complete.
* This method is used for user initiated kill operations, so the store operation happens before response is sent back to the user.
*/
public static ChangeAction userInitiateTaskKillAction(ReconciliationEngine<JobManagerReconcilerEvent> engine, JobServiceRuntime executionContext, JobStore jobStore, VersionSupplier versionSupplier, String taskId, boolean shrink, boolean preventMinSizeUpdate, String reasonCode, String reason, TitusRuntime titusRuntime, CallMetadata callMetadata) {
return TitusChangeAction.newAction("userInitiateTaskKill").id(taskId).trigger(V3JobOperations.Trigger.API).summary(reason).callMetadata(callMetadata).changeWithModelUpdates(self -> JobEntityHolders.toTaskObservable(engine, taskId, titusRuntime).flatMap(task -> {
TaskState taskState = task.getStatus().getState();
if (taskState == TaskState.KillInitiated || taskState == TaskState.Finished) {
return Observable.just(Collections.<ModelActionHolder>emptyList());
}
if (shrink) {
Job<ServiceJobExt> job = engine.getReferenceView().getEntity();
Capacity capacity = job.getJobDescriptor().getExtensions().getCapacity();
if (preventMinSizeUpdate && capacity.getDesired() <= capacity.getMin()) {
return Observable.<List<ModelActionHolder>>error(JobManagerException.terminateAndShrinkNotAllowed(job, task));
}
}
Task taskWithKillInitiated = VersionSuppliers.nextVersion(JobFunctions.changeTaskStatus(task, TaskState.KillInitiated, reasonCode, reason, titusRuntime.getClock()), versionSupplier);
Callable<List<ModelActionHolder>> modelUpdateActions = () -> JobEntityHolders.expectTask(engine, task.getId(), titusRuntime).map(current -> {
List<ModelActionHolder> updateActions = new ArrayList<>();
TitusModelAction stateUpdateAction = TitusModelAction.newModelUpdate(self).taskUpdate(taskWithKillInitiated);
updateActions.addAll(ModelActionHolder.allModels(stateUpdateAction));
if (shrink) {
TitusModelAction shrinkAction = createShrinkAction(self, versionSupplier);
updateActions.add(ModelActionHolder.reference(shrinkAction));
}
return updateActions;
}).orElse(Collections.emptyList());
return jobStore.updateTask(taskWithKillInitiated).andThen(createKillAction(executionContext, task)).andThen(Observable.fromCallable(modelUpdateActions));
}));
}
use of com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt in project titus-control-plane by Netflix.
the class ServiceDifferenceResolver method applyStore.
private List<ChangeAction> applyStore(ReconciliationEngine<JobManagerReconcilerEvent> engine, ServiceJobView refJobView, EntityHolder storeJob, AtomicInteger allowedNewTasks) {
if (!storeWriteRetryInterceptor.executionLimits(storeJob)) {
return Collections.emptyList();
}
List<ChangeAction> actions = new ArrayList<>();
EntityHolder refJobHolder = refJobView.getJobHolder();
Job<ServiceJobExt> refJob = refJobHolder.getEntity();
if (!refJobHolder.getEntity().equals(storeJob.getEntity())) {
actions.add(storeWriteRetryInterceptor.apply(BasicJobActions.updateJobInStore(engine, jobStore)));
}
boolean isJobTerminating = refJob.getStatus().getState() == JobState.KillInitiated;
for (EntityHolder referenceTaskHolder : refJobHolder.getChildren()) {
ServiceJobTask refTask = referenceTaskHolder.getEntity();
Optional<EntityHolder> storeHolder = storeJob.findById(referenceTaskHolder.getId());
ServiceJobTask storeTask = storeHolder.get().getEntity();
boolean refAndStoreInSync = areEquivalent(storeHolder.get(), referenceTaskHolder);
boolean shouldRetry = !isJobTerminating && refTask.getStatus().getState() == TaskState.Finished && !refTask.getStatus().getReasonCode().equals(TaskStatus.REASON_SCALED_DOWN) && allowedNewTasks.get() > 0;
if (refAndStoreInSync) {
TaskState currentTaskState = refTask.getStatus().getState();
if (currentTaskState == TaskState.Finished) {
if (isJobTerminating || isScaledDown(storeTask) || hasEnoughTasksRunning(refJobView)) {
actions.add(removeFinishedServiceTaskAction(jobStore, storeTask));
} else if (shouldRetry && TaskRetryers.shouldRetryNow(referenceTaskHolder, clock)) {
createNewTaskAction(refJobView, Optional.of(referenceTaskHolder), Collections.emptyList(), Collections.emptyList()).ifPresent(actions::add);
}
}
} else {
Task task = referenceTaskHolder.getEntity();
CallMetadata callMetadata = RECONCILER_CALLMETADATA.toBuilder().withCallReason("Writing runtime state changes to store").build();
actions.add(storeWriteRetryInterceptor.apply(BasicTaskActions.writeReferenceTaskToStore(jobStore, engine, task.getId(), callMetadata, titusRuntime)));
}
// Both current and delayed retries are counted
if (shouldRetry) {
allowedNewTasks.decrementAndGet();
}
}
return actions;
}
use of com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt in project titus-control-plane by Netflix.
the class DefaultLoadBalancerJobValidatorTest method testValidateMaxLoadBalancers.
@Test
public void testValidateMaxLoadBalancers() throws Exception {
when(jobOperations.getJob(JOB_ID)).thenReturn(Optional.of(Job.<ServiceJobExt>newBuilder().withId(JOB_ID).withStatus(JobStatus.newBuilder().withState(JobState.Accepted).build()).withJobDescriptor(JobDescriptor.<ServiceJobExt>newBuilder().withExtensions(ServiceJobExt.newBuilder().build()).withContainer(Container.newBuilder().withImage(Image.newBuilder().build()).withContainerResources(ContainerResources.newBuilder().withAllocateIP(true).build()).build()).build()).build()));
when(loadBalancerValidationConfiguration.getMaxLoadBalancersPerJob()).thenReturn(30);
for (int i = 0; i < loadBalancerValidationConfiguration.getMaxLoadBalancersPerJob() + 1; i++) {
loadBalancerStore.addOrUpdateLoadBalancer(new JobLoadBalancer(JOB_ID, "LoadBalancer-" + i), JobLoadBalancer.State.ASSOCIATED).await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
Throwable thrown = catchThrowable(() -> loadBalancerValidator.validateJobId(JOB_ID));
assertThat(thrown).isInstanceOf(LoadBalancerException.class);
assertThat(((LoadBalancerException) thrown).getErrorCode()).isEqualTo(LoadBalancerException.ErrorCode.JobMaxLoadBalancers);
}
use of com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt in project titus-control-plane by Netflix.
the class DefaultAppScaleManager method getJobScalingConstraints.
private JobScalingConstraints getJobScalingConstraints(String policyRefId, String jobId) {
// V3 API
if (v3JobOperations == null) {
return new JobScalingConstraints(0, 0);
}
Optional<Job<?>> job = v3JobOperations.getJob(jobId);
if (job.isPresent()) {
if (job.get().getJobDescriptor().getExtensions() instanceof ServiceJobExt) {
ServiceJobExt serviceJobExt = (ServiceJobExt) job.get().getJobDescriptor().getExtensions();
int minCapacity = serviceJobExt.getCapacity().getMin();
int maxCapacity = serviceJobExt.getCapacity().getMax();
return new JobScalingConstraints(minCapacity, maxCapacity);
} else {
logger.info("Not a service job (V3) {}", jobId);
throw AutoScalePolicyException.wrapJobManagerException(policyRefId, JobManagerException.notServiceJob(jobId));
}
} else {
throw AutoScalePolicyException.wrapJobManagerException(policyRefId, JobManagerException.jobNotFound(jobId));
}
}
Aggregations