Skip to content

Commit 1f47061

Browse files
committed
fix: non primary Pod with pending restart instance are not restarted
1 parent 006e008 commit 1f47061

1 file changed

Lines changed: 75 additions & 57 deletions

File tree

stackgres-k8s/src/operator/src/main/java/io/stackgres/operator/conciliation/cluster/ClusterStatefulSetWithPrimaryReconciliationHandler.java

Lines changed: 75 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,12 @@ private StatefulSet concileSts(
224224
requiredSts.getMetadata().getNamespace());
225225
final Map<String, String> appLabel = labelFactory.appLabel();
226226
final List<Pod> currentPods = findStatefulSetPods(requiredSts, appLabel);
227+
final var patroniCtl = this.patroniCtl.instanceFor(context);
228+
final List<PatroniMember> patroniMembers = patroniCtl.list();
227229
final boolean isRolloutAllowed = ClusterRolloutUtil.isRolloutAllowed(context);
228230
final boolean isReducedImpact = ClusterRolloutUtil.isRolloutReducedImpact(context);
229231
final boolean requiresRestart = ClusterRolloutUtil
230-
.getRestartReasons(context, currentSts, currentPods, List.of())
232+
.getRestartReasons(context, currentSts, currentPods, patroniMembers)
231233
.requiresRestart();
232234

233235
final int desiredReplicas;
@@ -243,7 +245,6 @@ private StatefulSet concileSts(
243245
}
244246
final int lastReplicaIndex = desiredReplicas - 1;
245247

246-
final var patroniCtl = this.patroniCtl.instanceFor(context);
247248
final Optional<String> latestPrimaryFromPatroni =
248249
PatroniUtil.getLatestPrimaryFromPatroni(patroniCtl);
249250
if (desiredReplicas > 0) {
@@ -346,7 +347,8 @@ private void performRollout(
346347
.getRestartReasons(context, Optional.of(updatedSts), pod, List.of())
347348
.getReasons().contains(RestartReason.STATEFULSET))
348349
.findAny();
349-
if (anyOtherPodAndPendingRestart.isPresent()) {
350+
if (foundPrimaryPod.isEmpty()
351+
&& anyOtherPodAndPendingRestart.isPresent()) {
350352
if (LOGGER.isDebugEnabled()) {
351353
LOGGER.debug("Restarting non primary Pod {} since pending restart",
352354
anyOtherPodAndPendingRestart.get().getMetadata().getName());
@@ -387,7 +389,24 @@ private void performRollout(
387389
foundPrimaryPod.get().getMetadata().getName());
388390
}
389391
var credentials = getPatroniCredentials(context.getMetadata().getName(), context.getMetadata().getNamespace());
390-
patroniCtl.restart(credentials.v1, credentials.v2, foundPrimaryPod.get().getMetadata().getName());
392+
patroniCtl.restart(credentials.v1, credentials.v2,
393+
foundPrimaryPod.get().getMetadata().getName());
394+
return;
395+
}
396+
var anyOtherPodAndPendingRestartInstance = otherPods
397+
.stream()
398+
.filter(pod -> patroniMembers.stream()
399+
.anyMatch(patroniMember -> patroniMember.getMember().equals(pod.getMetadata().getName())
400+
&& patroniMember.getPendingRestart() != null))
401+
.findFirst();
402+
if (anyOtherPodAndPendingRestartInstance.isPresent()) {
403+
if (LOGGER.isDebugEnabled()) {
404+
LOGGER.debug("Restarting Postgres instance of non primary Pod {} since pending restart",
405+
anyOtherPodAndPendingRestartInstance.get().getMetadata().getName());
406+
}
407+
var credentials = getPatroniCredentials(context.getMetadata().getName(), context.getMetadata().getNamespace());
408+
patroniCtl.restart(credentials.v1, credentials.v2,
409+
anyOtherPodAndPendingRestartInstance.get().getMetadata().getName());
391410
return;
392411
}
393412
if (foundPrimaryPod.isPresent()
@@ -408,62 +427,61 @@ private void performRollout(
408427
handler.delete(context, anyOtherPodAndPendingRestartAnyReason.get());
409428
return;
410429
}
411-
final Optional<PatroniMember> leastLagPatroniMemberAndReady =
412-
patroniMembers
413-
.stream()
414-
.filter(PatroniMember::isReplica)
415-
.filter(PatroniMember::isRunning)
416-
.filter(member -> Optional.ofNullable(member.getTags())
417-
.filter(tags -> tags.entrySet().stream().anyMatch(
418-
tag -> tag.getKey().equals(PatroniUtil.NOFAILOVER_TAG)
419-
&& tag.getValue() != null && tag.getValue().getValue() != null
420-
&& Objects.equals(tag.getValue().getValue().toString(), Boolean.TRUE.toString())))
421-
.isEmpty())
422-
.min((m1, m2) -> {
423-
var l1 = Optional.ofNullable(m1.getLagInMb())
424-
.map(IntOrString::getIntVal);
425-
var l2 = Optional.ofNullable(m2.getLagInMb())
426-
.map(IntOrString::getIntVal);
427-
if (l1.isPresent() && l2.isPresent()) {
428-
return l1.get().compareTo(l2.get());
429-
} else if (l1.isPresent() && l2.isEmpty()) {
430-
return -1;
431-
} else if (l1.isEmpty() && l2.isPresent()) {
432-
return 1;
433-
} else {
434-
return 0;
435-
}
436-
});
437-
final Optional<Pod> otherLeastLagPodAndReady = leastLagPatroniMemberAndReady
438-
.stream()
439-
.flatMap(member -> otherPods
440-
.stream()
441-
.filter(ClusterRolloutUtil::isPodReady)
442-
.filter(pod -> member.getMember().equals(pod.getMetadata().getName())))
443-
.findFirst();
444-
if (foundPrimaryPodAndPendingRestart.isPresent()
445-
&& otherLeastLagPodAndReady.isPresent()) {
446-
if (LOGGER.isDebugEnabled()) {
447-
LOGGER.debug("Failover primary Pod {} to Pod {} since ready and with least lag",
430+
if (foundPrimaryPodAndPendingRestart.isPresent()) {
431+
final Optional<PatroniMember> leastLagPatroniMemberAndReady =
432+
patroniMembers
433+
.stream()
434+
.filter(PatroniMember::isReplica)
435+
.filter(PatroniMember::isRunning)
436+
.filter(member -> Optional.ofNullable(member.getTags())
437+
.filter(tags -> tags.entrySet().stream().anyMatch(
438+
tag -> tag.getKey().equals(PatroniUtil.NOFAILOVER_TAG)
439+
&& tag.getValue() != null && tag.getValue().getValue() != null
440+
&& Objects.equals(tag.getValue().getValue().toString(), Boolean.TRUE.toString())))
441+
.isEmpty())
442+
.min((m1, m2) -> {
443+
var l1 = Optional.ofNullable(m1.getLagInMb())
444+
.map(IntOrString::getIntVal);
445+
var l2 = Optional.ofNullable(m2.getLagInMb())
446+
.map(IntOrString::getIntVal);
447+
if (l1.isPresent() && l2.isPresent()) {
448+
return l1.get().compareTo(l2.get());
449+
} else if (l1.isPresent() && l2.isEmpty()) {
450+
return -1;
451+
} else if (l1.isEmpty() && l2.isPresent()) {
452+
return 1;
453+
} else {
454+
return 0;
455+
}
456+
});
457+
final Optional<Pod> otherLeastLagPodAndReady = leastLagPatroniMemberAndReady
458+
.stream()
459+
.flatMap(member -> otherPods
460+
.stream()
461+
.filter(ClusterRolloutUtil::isPodReady)
462+
.filter(pod -> member.getMember().equals(pod.getMetadata().getName())))
463+
.findFirst();
464+
if (otherLeastLagPodAndReady.isPresent()) {
465+
if (LOGGER.isDebugEnabled()) {
466+
LOGGER.debug("Failover primary Pod {} to Pod {} since ready and with least lag",
467+
foundPrimaryPod.get().getMetadata().getName(),
468+
otherLeastLagPodAndReady.get().getMetadata().getName());
469+
}
470+
var credentials = getPatroniCredentials(context.getMetadata().getName(), context.getMetadata().getNamespace());
471+
patroniCtl.switchover(
472+
credentials.v1,
473+
credentials.v2,
448474
foundPrimaryPod.get().getMetadata().getName(),
449475
otherLeastLagPodAndReady.get().getMetadata().getName());
476+
return;
477+
} else {
478+
if (LOGGER.isDebugEnabled()) {
479+
LOGGER.debug("Restarting primary Pod {} since pending restart",
480+
foundPrimaryPodAndPendingRestart.get().getMetadata().getName());
481+
}
482+
handler.delete(context, foundPrimaryPodAndPendingRestart.get());
483+
return;
450484
}
451-
var credentials = getPatroniCredentials(context.getMetadata().getName(), context.getMetadata().getNamespace());
452-
patroniCtl.switchover(
453-
credentials.v1,
454-
credentials.v2,
455-
foundPrimaryPod.get().getMetadata().getName(),
456-
otherLeastLagPodAndReady.get().getMetadata().getName());
457-
return;
458-
}
459-
if (foundPrimaryPodAndPendingRestart.isPresent()
460-
&& otherLeastLagPodAndReady.isEmpty()) {
461-
if (LOGGER.isDebugEnabled()) {
462-
LOGGER.debug("Restarting primary Pod {} since pending restart",
463-
foundPrimaryPodAndPendingRestart.get().getMetadata().getName());
464-
}
465-
handler.delete(context, foundPrimaryPodAndPendingRestart.get());
466-
return;
467485
}
468486
}
469487

0 commit comments

Comments
 (0)