From 5cb3900c67997477180f0a7758e1a18e55b7a1d7 Mon Sep 17 00:00:00 2001 From: sorcier Date: Thu, 12 Nov 2026 11:44:10 +0100 Subject: [PATCH] fix(update): v2.7.1 avoid transient Nginx 502 error during 1-click web update --- public/api.php | 1 + public/assets/app.js | 63 ++++++++++++++++++++++++++------------------ scripts/update.sh | 17 ++++++++---- version.json | 9 ++++++- 4 files changed, 59 insertions(+), 31 deletions(-) diff --git a/public/api.php b/public/api.php index 7c9ad3d..9aee60a 100644 --- a/public/api.php +++ b/public/api.php @@ -2621,6 +2621,7 @@ try { break; case 'run_update': + @set_time_limit(300); $output = []; $code = 0; exec("sudo /var/www/nexus-pbx/scripts/update.sh 2>&1", $output, $code); diff --git a/public/assets/app.js b/public/assets/app.js index fa4e86a..2a80d87 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -6412,11 +6412,29 @@ async function executeSystemUpdate() { showToast("Mise à jour en cours d'exécution en arrière-plan...", 'info'); + // Pause du polling métriques pour éviter un 502 Nginx pendant le reload php-fpm/nginx + stopMetricsPolling(); + // Purge préventive du cache local localStorage.removeItem('nexus_update_last_check_ts'); localStorage.removeItem('nexus_update_cached_data'); - function finalizeUpdateSuccess(newVer) { + async function probeUpdateReady(maxAttempts = 6, delayMs = 1500) { + for (let i = 0; i < maxAttempts; i++) { + await new Promise(r => setTimeout(r, delayMs)); + try { + const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now()); + if (!probeRes.ok) continue; + const probeData = await probeRes.json(); + if (probeData && probeData.success && probeData.current_version) { + return probeData; + } + } catch (_) {} + } + return null; + } + + async function finalizeUpdateSuccess(newVer) { newVer = String(newVer || '').replace(/^v/, ''); localStorage.setItem('nexus_update_last_check_ts', Date.now().toString()); localStorage.setItem('nexus_update_cached_data', JSON.stringify({ @@ -6449,10 +6467,11 @@ async function executeSystemUpdate() { btnModalConfirm.innerHTML = '✓ Mise à jour terminée ! Rechargement...'; } - setTimeout(() => { - closeUpdateConfirmModal(); - window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now(); - }, 1800); + // Attendre que le reload différé php-fpm/nginx soit terminé avant de recharger la page + await new Promise(r => setTimeout(r, 2500)); + await probeUpdateReady(5, 1000); + closeUpdateConfirmModal(); + window.location.href = window.location.origin + window.location.pathname + '?_t=' + Date.now(); } try { @@ -6476,18 +6495,15 @@ async function executeSystemUpdate() { } // Si la réponse n'était pas un JSON valide ou a été interrompue par le rechargement de php-fpm/nginx, - // on sonde le serveur pour vérifier si la mise à jour a en réalité bien été appliquée sur le disque - await new Promise(r => setTimeout(r, 2000)); - try { - const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now()); - const probeData = await probeRes.json(); - if (probeData && probeData.success && probeData.current_version) { - finalizeUpdateSuccess(probeData.current_version); - return; - } - } catch (_) {} + // on sonde le serveur à plusieurs reprises pour laisser Nginx/PHP-FPM terminer leur reload + const probeData = await probeUpdateReady(6, 1500); + if (probeData) { + await finalizeUpdateSuccess(probeData.current_version); + return; + } // En cas d'échec réel avéré + startMetricsPolling(); closeUpdateConfirmModal(); const errMsg = (data && (data.output || data.message)) ? (data.output || data.message) : (rawText.slice(0, 150) || "Erreur inconnue"); alert("Erreur lors de la mise à jour :\n\n" + errMsg); @@ -6503,17 +6519,14 @@ async function executeSystemUpdate() { } catch (e) { // En cas d'interruption réseau du socket (Safari WebKit DOMException ou timeout), - // on vérifie avant d'alerter si le serveur a quand même réussi à déployer les fichiers - await new Promise(r => setTimeout(r, 2000)); - try { - const probeRes = await fetch('/api.php?action=check_update&_t=' + Date.now()); - const probeData = await probeRes.json(); - if (probeData && probeData.success && probeData.current_version) { - finalizeUpdateSuccess(probeData.current_version); - return; - } - } catch (_) {} + // on vérifie à plusieurs reprises si le serveur a quand même réussi à déployer les fichiers + const probeData = await probeUpdateReady(6, 1500); + if (probeData) { + await finalizeUpdateSuccess(probeData.current_version); + return; + } + startMetricsPolling(); closeUpdateConfirmModal(); alert("Erreur réseau lors de la mise à jour : " + (e.message || "Connexion interrompue")); if (btnRun) { diff --git a/scripts/update.sh b/scripts/update.sh index 58c8252..07b585e 100755 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -261,7 +261,7 @@ if [ -t 1 ]; then systemctl reload nginx 2>/dev/null || true fail2ban-client reload >/dev/null 2>&1 || true else - (nohup bash -c "sleep 2 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true; fail2ban-client reload >/dev/null 2>&1 || true" >/dev/null 2>&1 &) + (nohup bash -c "sleep 1 && (systemctl reload php8.4-fpm 2>/dev/null || systemctl reload php8.2-fpm 2>/dev/null || systemctl reload php*-fpm 2>/dev/null || true); systemctl reload nginx 2>/dev/null || true; fail2ban-client reload >/dev/null 2>&1 || true" /dev/null 2>&1 &) fi NEW_VER="Inconnue" @@ -279,10 +279,17 @@ echo "" if [ -f "$APP_DIR/version.json" ]; then echo -e "${C_CYAN}${C_BOLD}Nouveautés de cette version :${C_RESET}" php -r ' - $v = json_decode(file_get_contents("/var/www/nexus-pbx/version.json"), true); - if (!empty($v["changelog"])) { - foreach ($v["changelog"] as $line) { - echo " • " . $line . "\n"; + $v = json_decode(@file_get_contents("/var/www/nexus-pbx/version.json"), true); + if (!empty($v["changelog"]) && is_array($v["changelog"])) { + $first = $v["changelog"][0]; + if (is_array($first) && !empty($first["changes"])) { + foreach ($first["changes"] as $line) { + echo " • " . $line . "\n"; + } + } else { + foreach ($v["changelog"] as $line) { + if (is_string($line)) echo " • " . $line . "\n"; + } } } ' diff --git a/version.json b/version.json index 982440d..901ae86 100644 --- a/version.json +++ b/version.json @@ -1,9 +1,16 @@ { - "version": "2.7.0", + "version": "2.7.1", "codename": "Pulsar UCP", "release_date": "2026-11-12", "min_php_version": "8.2", "changelog": [ + { + "version": "2.7.1", + "date": "2026-11-12", + "changes": [ + "Mise à jour 1-Clic : Suppression de l'erreur Nginx 502 transitoire après mise à jour (pause du polling métriques, attente du reload PHP-FPM/Nginx avec sonde multi-essais avant rechargement de la page, fermeture stdin dans update.sh)" + ] + }, { "version": "2.7.0", "date": "2026-11-12",