getSyncReplicasData computes the actual number of required synchronous replicas and the names of the electable sync replicas given the requested min, max, the number of ready replicas in the cluster and the sync replicas constraints (if any)
( ctx context.Context, cluster *apiv1.Cluster, )
| 53 | // the electable sync replicas given the requested min, max, the number of ready replicas in the cluster and the sync |
| 54 | // replicas constraints (if any) |
| 55 | func getSyncReplicasData( |
| 56 | ctx context.Context, |
| 57 | cluster *apiv1.Cluster, |
| 58 | ) (syncReplicas int, electableSyncReplicas []string) { |
| 59 | contextLogger := log.FromContext(ctx) |
| 60 | |
| 61 | // We start with the number of healthy replicas (healthy pods minus one) |
| 62 | // and verify it is greater than 0 and between minSyncReplicas and maxSyncReplicas. |
| 63 | // Formula: 1 <= minSyncReplicas <= SyncReplicas <= maxSyncReplicas < readyReplicas |
| 64 | readyReplicas := len(cluster.Status.InstancesStatus[apiv1.PodHealthy]) - 1 |
| 65 | |
| 66 | // If the number of ready replicas is negative, |
| 67 | // there are no healthy Pods so no sync replica can be configured |
| 68 | if readyReplicas < 0 { |
| 69 | return 0, nil |
| 70 | } |
| 71 | |
| 72 | // Initially set it to the max sync replicas requested by user |
| 73 | syncReplicas = cluster.Spec.MaxSyncReplicas |
| 74 | |
| 75 | // Lower to min sync replicas if not enough ready replicas |
| 76 | if readyReplicas < syncReplicas { |
| 77 | syncReplicas = cluster.Spec.MinSyncReplicas |
| 78 | } |
| 79 | |
| 80 | // Lower to ready replicas if min sync replicas is too high |
| 81 | // (this is a self-healing procedure that prevents from a |
| 82 | // temporarily unresponsive system) |
| 83 | if readyReplicas < cluster.Spec.MinSyncReplicas { |
| 84 | syncReplicas = readyReplicas |
| 85 | contextLogger.Warning("Ignore minSyncReplicas to enforce self-healing", |
| 86 | "syncReplicas", readyReplicas, |
| 87 | "minSyncReplicas", cluster.Spec.MinSyncReplicas, |
| 88 | "maxSyncReplicas", cluster.Spec.MaxSyncReplicas) |
| 89 | } |
| 90 | |
| 91 | electableSyncReplicas = getElectableSyncReplicas(ctx, cluster) |
| 92 | numberOfElectableSyncReplicas := len(electableSyncReplicas) |
| 93 | if numberOfElectableSyncReplicas < syncReplicas { |
| 94 | contextLogger.Warning("lowering sync replicas due to not enough electable instances for sync replication "+ |
| 95 | "given the constraints", |
| 96 | "electableSyncReplicasWithoutConstraints", syncReplicas, |
| 97 | "electableSyncReplicasWithConstraints", numberOfElectableSyncReplicas, |
| 98 | "constraints", cluster.Spec.PostgresConfiguration.SyncReplicaElectionConstraint) |
| 99 | syncReplicas = numberOfElectableSyncReplicas |
| 100 | } |
| 101 | |
| 102 | return syncReplicas, electableSyncReplicas |
| 103 | } |
| 104 | |
| 105 | // getElectableSyncReplicas computes the names of the instances that can be elected to sync replicas |
| 106 | func getElectableSyncReplicas(ctx context.Context, cluster *apiv1.Cluster) []string { |
no test coverage detected