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 {
|
try {
|
||||||
$cm = new ClusterManager($db);
|
$cm = new ClusterManager($db);
|
||||||
$cSet = $cm->getSettings();
|
$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();
|
$syncRes = $cm->pushSyncToPeer();
|
||||||
$clusterSyncMsg = $syncRes['message'] ?? 'Réplication pair OK';
|
$clusterSyncMsg = $syncRes['message'] ?? 'Réplication pair OK';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,12 @@ use App\Database;
|
|||||||
use App\ClusterManager;
|
use App\ClusterManager;
|
||||||
|
|
||||||
try {
|
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();
|
$db = Database::getConnection();
|
||||||
$cm = new ClusterManager($db);
|
$cm = new ClusterManager($db);
|
||||||
$st = $cm->getSettings();
|
$st = $cm->getSettings();
|
||||||
@@ -23,13 +29,10 @@ try {
|
|||||||
exit(0);
|
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'] ?? '';
|
$vip = $st['virtual_ip'] ?? '';
|
||||||
$isVipActive = $cm->isVirtualIpActive($vip);
|
if (empty($vip) || !$cm->isVirtualIpActive($vip)) {
|
||||||
$configuredRole = $st['role'] ?? 'master';
|
|
||||||
|
|
||||||
// Un esclave (backup) ne doit jamais écraser le maître
|
|
||||||
if ($configuredRole !== 'master' && !$isVipActive) {
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -203,12 +203,13 @@ class ClusterManager
|
|||||||
*/
|
*/
|
||||||
public function isVirtualIpActive(string $vip): bool
|
public function isVirtualIpActive(string $vip): bool
|
||||||
{
|
{
|
||||||
if ($vip === '') {
|
$cleanVip = explode('/', trim($vip))[0] ?? '';
|
||||||
|
if ($cleanVip === '') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$output = shell_exec('ip -o -4 addr show 2>/dev/null') ?: '';
|
$output = shell_exec('ip -o -4 addr show 2>/dev/null') ?: '';
|
||||||
foreach (preg_split('/\r?\n/', $output) ?: [] as $line) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user