use of com.netflix.titus.api.clustermembership.model.ClusterMember in project titus-control-plane by Netflix.
the class DefaultClusterMembershipService method clusterStateEvaluator.
private Mono<Void> clusterStateEvaluator(ExecutionContext context) {
return Mono.defer(() -> {
ClusterMember localMember = connector.getLocalClusterMemberRevision().getCurrent();
ClusterMemberLeadershipState localLeadershipState = connector.getLocalLeadershipRevision().getCurrent().getLeadershipState();
HealthStatus health = healthIndicator.health();
// Explicitly disabled
if (!configuration.isLeaderElectionEnabled() || !localMember.isEnabled()) {
if (localLeadershipState == ClusterMemberLeadershipState.NonLeader) {
logger.info("Local member excluded from the leader election. Leaving the leader election process");
return connector.leaveLeadershipGroup(true).flatMap(success -> success ? connector.register(current -> toInactive(current, "Marked by a user as disabled")).ignoreElement().cast(Void.class) : Mono.empty());
}
if (localLeadershipState == ClusterMemberLeadershipState.Disabled && localMember.isActive()) {
return connector.register(current -> toInactive(current, "Marked by a user as disabled")).ignoreElement().cast(Void.class);
}
return Mono.empty();
}
// Re-enable if healthy
if (health.getHealthState() == HealthState.Healthy) {
if (localLeadershipState == ClusterMemberLeadershipState.Disabled) {
logger.info("Re-enabling local member which is in the disabled state");
return connector.joinLeadershipGroup().then(connector.register(this::toActive).ignoreElement().cast(Void.class));
}
if (!localMember.isActive()) {
return connector.register(this::toActive).ignoreElement().cast(Void.class);
}
return Mono.empty();
}
// Disable if unhealthy (and not the leader)
if (localLeadershipState != ClusterMemberLeadershipState.Disabled && localLeadershipState != ClusterMemberLeadershipState.Leader) {
logger.info("Disabling local member as it is unhealthy: {}", health);
return connector.leaveLeadershipGroup(true).flatMap(success -> success ? connector.register(current -> toInactive(current, "Unhealthy: " + health)).ignoreElement().cast(Void.class) : Mono.empty());
}
if (localLeadershipState == ClusterMemberLeadershipState.Disabled && localMember.isActive()) {
return connector.register(current -> toInactive(current, "Unhealthy: " + health)).ignoreElement().cast(Void.class);
}
return Mono.empty();
}).doOnError(error -> {
logger.info("Cluster membership health evaluation error: {}", error.getMessage());
logger.debug("Stack trace", error);
}).doOnTerminate(() -> {
metrics.updateLocal(connector.getLocalLeadershipRevision().getCurrent().getLeadershipState(), healthIndicator.health());
metrics.updateSiblings(connector.getClusterMemberSiblings());
});
}
use of com.netflix.titus.api.clustermembership.model.ClusterMember in project titus-control-plane by Netflix.
the class KubeClusterMembershipConnectorTest method doRegistrationChange.
private ClusterMembershipRevision<ClusterMember> doRegistrationChange(Supplier<ClusterMembershipRevision<ClusterMember>> action) throws InterruptedException {
long now = titusRuntime.getClock().wallTime();
ClusterMembershipRevision<ClusterMember> newRevision = action.get();
assertThat(newRevision.getTimestamp()).isGreaterThanOrEqualTo(now);
assertThat(connector.getLocalClusterMemberRevision()).isEqualTo(newRevision);
ClusterMembershipEvent registrationEvent1 = connectorEvents.takeNext(TIMEOUT);
assertThat(registrationEvent1).isInstanceOf(ClusterMembershipChangeEvent.class);
assertThat(((ClusterMembershipChangeEvent) registrationEvent1).getChangeType()).isEqualTo(ClusterMembershipChangeEvent.ChangeType.Updated);
return newRevision;
}
use of com.netflix.titus.api.clustermembership.model.ClusterMember in project titus-control-plane by Netflix.
the class MultiNodeClusterMemberResolver method buildSnapshot.
private ClusterMembershipSnapshot buildSnapshot() {
if (memberResolversByIpAddress.isEmpty()) {
return ClusterMembershipSnapshot.empty();
}
List<ClusterMembershipSnapshot> healthySnapshots = findHealthySnapshots();
ClusterMembershipSnapshot.Builder builder = ClusterMembershipSnapshot.newBuilder();
Map<String, List<ClusterMembershipRevision<ClusterMember>>> grouped = healthySnapshots.stream().flatMap(snapshot -> snapshot.getMemberRevisions().values().stream()).collect(Collectors.groupingBy(m -> m.getCurrent().getMemberId()));
List<ClusterMembershipRevision<ClusterMember>> recentRevisions = grouped.values().stream().map(this::findBestMemberRevision).collect(Collectors.toList());
builder.withMemberRevisions(recentRevisions);
// Find leader
Optional<ClusterMembershipRevision<ClusterMemberLeadership>> recentLeader = Optional.empty();
for (ClusterMembershipSnapshot snapshot : healthySnapshots) {
if (snapshot.getLeaderRevision().isPresent()) {
if (recentLeader.isPresent()) {
if (recentLeader.get().getRevision() < snapshot.getLeaderRevision().get().getRevision()) {
recentLeader = snapshot.getLeaderRevision();
}
} else {
recentLeader = snapshot.getLeaderRevision();
}
}
}
recentLeader.ifPresent(builder::withLeaderRevision);
// Choose latest version of each
long minStaleness = healthySnapshots.stream().mapToLong(ClusterMembershipSnapshot::getStalenessMs).min().orElse(0);
builder.withStalenessMs(minStaleness);
return builder.build();
}
use of com.netflix.titus.api.clustermembership.model.ClusterMember in project titus-control-plane by Netflix.
the class ClusterMemberGenerator method clusterMemberUpdateRevision.
public static ClusterMembershipRevision<ClusterMember> clusterMemberUpdateRevision(ClusterMembershipRevision<ClusterMember> currentRevision) {
long now = System.currentTimeMillis();
ClusterMember current = currentRevision.getCurrent();
return ClusterMembershipRevision.<ClusterMember>newBuilder().withCurrent(current.toBuilder().withLabels(CollectionsExt.copyAndAdd(current.getLabels(), "changedAt", "" + now)).build()).withCode("updated").withMessage("Random update to generate next revision number").withRevision(currentRevision.getRevision() + 1).withTimestamp(now).build();
}
Aggregations