Search in sources :

Example 1 with EntityHolder

use of com.netflix.titus.common.framework.reconciler.EntityHolder in project titus-control-plane by Netflix.

the class DefaultReconciliationEngine method startNextReferenceChangeAction.

private boolean startNextReferenceChangeAction() {
    try {
        ChangeActionHolder actionHolder;
        List<Transaction> transactions = new ArrayList<>();
        List<EntityHolder> changePoints = new ArrayList<>();
        while ((actionHolder = referenceChangeActions.peek()) != null) {
            // Ignore all unsubscribed actions
            Subscriber<Void> subscriber = actionHolder.getSubscriber();
            if (subscriber.isUnsubscribed()) {
                referenceChangeActions.poll();
                continue;
            }
            // Emit errors if the change point (EntityHolder for the action) not found
            Optional<EntityHolder> changePointOpt = modelHolder.getReference().findById(actionHolder.getEntityHolderId());
            if (!changePointOpt.isPresent()) {
                referenceChangeActions.poll();
                transactions.add(new FailedTransaction<>(this, actionHolder, new IllegalStateException("Entity holder not found: id=" + actionHolder.getEntityHolderId())));
                continue;
            }
            // Check if the current item overlaps with the already taken actions
            EntityHolder changePoint = changePointOpt.get();
            if (!changePoints.isEmpty() && isOverlapping(changePoint, changePoints)) {
                break;
            }
            // Create transaction
            changePoints.add(changePoint);
            Transaction transaction;
            try {
                transaction = new SingleTransaction<>(this, actionHolder.getChangeAction(), actionHolder.getCreateTimestamp(), Optional.of(actionHolder.getSubscriber()), actionHolder.getTransactionId(), false);
            } catch (Exception e) {
                transaction = new FailedTransaction<>(this, actionHolder, e);
            }
            transactions.add(transaction);
            referenceChangeActions.poll();
        }
        if (transactions.isEmpty()) {
            return false;
        }
        pendingTransaction = transactions.size() == 1 ? transactions.get(0) : new CompositeTransaction(transactions);
        return true;
    } finally {
        metrics.updateChangeActionQueueSize(referenceChangeActions.size());
    }
}
Also used : ArrayList(java.util.ArrayList) EntityHolder(com.netflix.titus.common.framework.reconciler.EntityHolder)

Example 2 with EntityHolder

use of com.netflix.titus.common.framework.reconciler.EntityHolder in project titus-control-plane by Netflix.

the class DefaultReconciliationFramework method findEngineByChildId.

@Override
public Optional<Pair<ReconciliationEngine<EVENT>, EntityHolder>> findEngineByChildId(String childId) {
    InternalReconciliationEngine<EVENT> engine = idToEngineMapRef.get().get(childId);
    if (engine == null) {
        return Optional.empty();
    }
    EntityHolder rootHolder = engine.getReferenceView();
    if (rootHolder.getId().equals(childId)) {
        return Optional.empty();
    }
    return rootHolder.findChildById(childId).map(c -> Pair.of(engine, c));
}
Also used : EntityHolder(com.netflix.titus.common.framework.reconciler.EntityHolder)

Example 3 with EntityHolder

use of com.netflix.titus.common.framework.reconciler.EntityHolder in project titus-control-plane by Netflix.

the class SingleTransaction method applyModelUpdates.

@Override
public Optional<ModelHolder> applyModelUpdates(ModelHolder modelHolder) {
    if (transactionStep != TransactionStep.ChangeActionCompleted) {
        return Optional.empty();
    }
    this.transactionStep = TransactionStep.ModelsUpdated;
    if (modelActionHolders.isEmpty()) {
        return Optional.empty();
    }
    EntityHolder referenceRootHolder = modelHolder.getReference();
    EntityHolder runningRootHolder = modelHolder.getRunning();
    EntityHolder storeRootHolder = modelHolder.getStore();
    try {
        for (ModelActionHolder updateAction : modelActionHolders) {
            switch(updateAction.getModel()) {
                case Reference:
                    referenceRootHolder = applyModelUpdate(updateAction, referenceRootHolder).orElse(referenceRootHolder);
                    break;
                case Running:
                    runningRootHolder = applyModelUpdate(updateAction, runningRootHolder).orElse(runningRootHolder);
                    break;
                case Store:
                    storeRootHolder = applyModelUpdate(updateAction, storeRootHolder).orElse(storeRootHolder);
                    break;
            }
        }
    } catch (Exception e) {
        String message = String.format("Change action failure during model update for %s (%s)", referenceRootHolder.getId(), e.toString());
        logger.warn(message, e);
        engine.getTitusRuntime().getCodeInvariants().unexpectedError(message, e);
        this.changeActionError = e;
        this.transactionStep = TransactionStep.ChangeActionFailed;
        return Optional.empty();
    }
    return Optional.of(new ModelHolder(referenceRootHolder, runningRootHolder, storeRootHolder));
}
Also used : EntityHolder(com.netflix.titus.common.framework.reconciler.EntityHolder) ModelActionHolder(com.netflix.titus.common.framework.reconciler.ModelActionHolder)

Example 4 with EntityHolder

use of com.netflix.titus.common.framework.reconciler.EntityHolder in project titus-control-plane by Netflix.

the class DefaultReconciliationFrameworkTest method testFailingMultiEngineChangeAction.

@Test
public void testFailingMultiEngineChangeAction() {
    EntityHolder root1 = EntityHolder.newRoot("myRoot1", "myEntity1");
    EntityHolder root2 = EntityHolder.newRoot("myRoot2", "myEntity2");
    framework.newEngine(root1).subscribe();
    framework.newEngine(root2).subscribe();
    testScheduler.triggerActions();
    Observable<Void> multiChangeObservable = framework.changeReferenceModel(// Keep anonymous class instead of lambda for readability
    new MultiEngineChangeAction() {

        @Override
        public Observable<Map<String, List<ModelActionHolder>>> apply() {
            return Observable.error(new RuntimeException("simulated error"));
        }
    }, // Keep anonymous class instead of lambda for readability
    (id, modelUpdates) -> new ChangeAction() {

        @Override
        public Observable<List<ModelActionHolder>> apply() {
            return modelUpdates;
        }
    }, "myRoot1", "myRoot2");
    ExtTestSubscriber<Void> multiChangeSubscriber = new ExtTestSubscriber<>();
    multiChangeObservable.subscribe(multiChangeSubscriber);
    assertThat(multiChangeSubscriber.isError()).isTrue();
    String errorMessage = ExceptionExt.toMessageChain(multiChangeSubscriber.getError());
    assertThat(errorMessage).contains("simulated error");
}
Also used : ChangeAction(com.netflix.titus.common.framework.reconciler.ChangeAction) MultiEngineChangeAction(com.netflix.titus.common.framework.reconciler.MultiEngineChangeAction) ExtTestSubscriber(com.netflix.titus.testkit.rx.ExtTestSubscriber) MultiEngineChangeAction(com.netflix.titus.common.framework.reconciler.MultiEngineChangeAction) EntityHolder(com.netflix.titus.common.framework.reconciler.EntityHolder) Observable(rx.Observable) List(java.util.List) ModelActionHolder(com.netflix.titus.common.framework.reconciler.ModelActionHolder) Test(org.junit.Test)

Example 5 with EntityHolder

use of com.netflix.titus.common.framework.reconciler.EntityHolder in project titus-control-plane by Netflix.

the class DefaultReconciliationFrameworkTest method testMultiEngineChangeAction.

@Test
public void testMultiEngineChangeAction() {
    EntityHolder root1 = EntityHolder.newRoot("myRoot1", "myEntity1");
    EntityHolder root2 = EntityHolder.newRoot("myRoot2", "myEntity2");
    framework.newEngine(root1).subscribe();
    framework.newEngine(root2).subscribe();
    testScheduler.triggerActions();
    MultiEngineChangeAction multiEngineChangeAction = () -> Observable.just(ImmutableMap.of("myRoot1", ModelActionHolder.allModels(new SimpleModelUpdateAction(EntityHolder.newRoot("myRoot1", "myEntity1#v2"), true)), "myRoot2", ModelActionHolder.allModels(new SimpleModelUpdateAction(EntityHolder.newRoot("myRoot2", "myEntity2#v2"), true))));
    Map<String, List<ModelActionHolder>> holders = new HashMap<>();
    Observable<Void> multiChangeObservable = framework.changeReferenceModel(multiEngineChangeAction, (id, modelUpdates) -> {
        ChangeAction changeAction = () -> modelUpdates.doOnNext(next -> holders.put(id, next));
        return changeAction;
    }, "myRoot1", "myRoot2");
    verify(engine1, times(0)).changeReferenceModel(any());
    verify(engine2, times(0)).changeReferenceModel(any());
    ExtTestSubscriber<Void> multiChangeSubscriber = new ExtTestSubscriber<>();
    multiChangeObservable.subscribe(multiChangeSubscriber);
    assertThat(multiChangeSubscriber.isUnsubscribed()).isTrue();
    verify(engine1, times(1)).changeReferenceModel(any());
    verify(engine2, times(1)).changeReferenceModel(any());
    // one action per view (Running, Store, Reference)
    assertThat(holders.get("myRoot1")).hasSize(3);
    SimpleModelUpdateAction modelAction1 = (SimpleModelUpdateAction) holders.get("myRoot1").get(0).getAction();
    assertThat((String) modelAction1.getEntityHolder().getEntity()).isEqualTo("myEntity1#v2");
    // one action per view (Running, Store, Reference)
    assertThat(holders.get("myRoot2")).hasSize(3);
    SimpleModelUpdateAction modelAction2 = (SimpleModelUpdateAction) holders.get("myRoot2").get(0).getAction();
    assertThat((String) modelAction2.getEntityHolder().getEntity()).isEqualTo("myEntity2#v2");
}
Also used : ChangeAction(com.netflix.titus.common.framework.reconciler.ChangeAction) MultiEngineChangeAction(com.netflix.titus.common.framework.reconciler.MultiEngineChangeAction) ExtTestSubscriber(com.netflix.titus.testkit.rx.ExtTestSubscriber) HashMap(java.util.HashMap) MultiEngineChangeAction(com.netflix.titus.common.framework.reconciler.MultiEngineChangeAction) EntityHolder(com.netflix.titus.common.framework.reconciler.EntityHolder) List(java.util.List) Test(org.junit.Test)

Aggregations

EntityHolder (com.netflix.titus.common.framework.reconciler.EntityHolder)31 ArrayList (java.util.ArrayList)17 Task (com.netflix.titus.api.jobmanager.model.job.Task)12 ChangeAction (com.netflix.titus.common.framework.reconciler.ChangeAction)12 ModelActionHolder (com.netflix.titus.common.framework.reconciler.ModelActionHolder)12 TitusChangeAction (com.netflix.titus.master.jobmanager.service.common.action.TitusChangeAction)12 List (java.util.List)10 TaskState (com.netflix.titus.api.jobmanager.model.job.TaskState)7 TitusModelAction (com.netflix.titus.master.jobmanager.service.common.action.TitusModelAction)7 Job (com.netflix.titus.api.jobmanager.model.job.Job)6 TaskStatus (com.netflix.titus.api.jobmanager.model.job.TaskStatus)6 ServiceJobExt (com.netflix.titus.api.jobmanager.model.job.ext.ServiceJobExt)6 ReconciliationEngine (com.netflix.titus.common.framework.reconciler.ReconciliationEngine)6 JobManagerReconcilerEvent (com.netflix.titus.master.jobmanager.service.event.JobManagerReconcilerEvent)6 Test (org.junit.Test)6 JobFunctions (com.netflix.titus.api.jobmanager.model.job.JobFunctions)5 JobStore (com.netflix.titus.api.jobmanager.store.JobStore)5 CallMetadata (com.netflix.titus.api.model.callmetadata.CallMetadata)5 TitusRuntime (com.netflix.titus.common.runtime.TitusRuntime)5 Optional (java.util.Optional)5