fix(cluster): ensure only VIP holder pushes sync and prevent deadlocks with flock and strict VIP check
This commit is contained in:
1 parent
0b740da87e
commit
0b654c885c
3 files changed
+14
-9
No files matched your search
+2
-1
@@ -1798,7 +1798,8 @@ try {
|
||||
try {
|
||||
$cm = new ClusterManager($db);
|
||||
$cSet = $cm->getSettings();
|
||||
if (!empty($cSet['enabled']) && !empty($cSet['auto_sync']) && ($cSet['role'] ?? '') === 'master' && !empty($cSet['peer_ip'])) {
|
||||
$isVipActive = $cm->isVirtualIpActive($cSet['virtual_ip'] ?? '');
|
||||
if (!empty($cSet['enabled']) && !empty($cSet['auto_sync']) && $isVipActive && !empty($cSet['peer_ip'])) {
|
||||
$syncRes = $cm->pushSyncToPeer();
|
||||
$clusterSyncMsg = $syncRes['message'] ?? 'Réplication pair OK';
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ use App\Database;
|
||||
use App\ClusterManager;
|
||||
|
||||
try {
|
||||
// 0. Verrou d'exécution exclusif pour éviter les chevauchements
|
||||
$lockFp = @fopen('/tmp/nexus_cluster_cron.lock', 'c+');
|
||||
if (!$lockFp || !@flock($lockFp, LOCK_EX | LOCK_NB)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
$db = Database::getConnection();
|
||||
$cm = new ClusterManager($db);
|
||||
$st = $cm->getSettings();
|
||||
@@ -23,13 +29,10 @@ try {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// 2. Seul le nœud MASTER actif émet la synchronisation vers le nœud BACKUP
|
||||
// 2. Règle d'or HA : SEUL le nœud qui détient l'IP Virtuelle active (VIP) émet la réplication
|
||||
// Un nœud passif/standby ne doit JAMAIS écraser le nœud actif ni émettre en boucle croisée
|
||||
$vip = $st['virtual_ip'] ?? '';
|
||||
$isVipActive = $cm->isVirtualIpActive($vip);
|
||||
$configuredRole = $st['role'] ?? 'master';
|
||||
|
||||
// Un esclave (backup) ne doit jamais écraser le maître
|
||||
if ($configuredRole !== 'master' && !$isVipActive) {
|
||||
if (empty($vip) || !$cm->isVirtualIpActive($vip)) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,12 +203,13 @@ class ClusterManager
|
||||
*/
|
||||
public function isVirtualIpActive(string $vip): bool
|
||||
{
|
||||
if ($vip === '') {
|
||||
$cleanVip = explode('/', trim($vip))[0] ?? '';
|
||||
if ($cleanVip === '') {
|
||||
return false;
|
||||
}
|
||||
$output = shell_exec('ip -o -4 addr show 2>/dev/null') ?: '';
|
||||
foreach (preg_split('/\r?\n/', $output) ?: [] as $line) {
|
||||
if (preg_match('/\sinet\s+' . preg_quote($vip, '/') . '\//', $line)) {
|
||||
if (preg_match('/\sinet\s+' . preg_quote($cleanVip, '/') . '(\/|\s)/', $line)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user