Archivage : verrou exclusif par boîtier, chdir dans cron_quarantaine
This commit is contained in:
+24
-7
@@ -1,14 +1,17 @@
|
||||
<?php
|
||||
// ============================================================================
|
||||
// cron_archivage.php - Traitement périodique des archives de la flotte
|
||||
// (cf synthèse §32-36). Exécuté via cron, dans le conteneur ship2net-php :
|
||||
// docker exec ship2net-php php /var/www/cron_archivage.php
|
||||
// (cf synthèse §32-40, §43). Exécuté NATIVEMENT sur le VPS (pas dans le
|
||||
// conteneur ship2net-php, cf synthèse §38.1), de façon planifiée :
|
||||
// /usr/bin/php /var/www/cron_archivage.php
|
||||
//
|
||||
// Construction progressive, bloc par bloc :
|
||||
// Bloc 1 (ce fichier) : résolution des bateaux actifs + liste des archives
|
||||
// en attente sur chacun.
|
||||
// Blocs suivants (à venir) : récupération, vérification d'intégrité,
|
||||
// résolution de génération, chargement, confirmation.
|
||||
// Pour chaque boîtier connu (TB_Cartes avec une adresse NetBird) : liste des
|
||||
// archives en attente sur son API, récupération, vérification d'intégrité,
|
||||
// déchiffrement, affectation/MMSI (quarantaine si besoin), génération,
|
||||
// chargement, enregistrement dans TB_Archives_traitees, confirmation de
|
||||
// suppression côté CM5. Chaque boîtier est traité sous verrou exclusif
|
||||
// (Verrouiller_boitier(), synthèse §44.6) : un boîtier déjà en cours de
|
||||
// traitement par un autre processus est sauté pour ce passage.
|
||||
// ============================================================================
|
||||
|
||||
// Certains fichiers du site (fonctions_mail.php notamment) utilisent des
|
||||
@@ -315,6 +318,15 @@ function Executer_cron_archivage()
|
||||
foreach ($boitiers as $boitier)
|
||||
{
|
||||
$adresse_mac = $boitier['Adresse_mac'];
|
||||
$verrou = Verrouiller_boitier($adresse_mac);
|
||||
if (!$verrou['ok'])
|
||||
{
|
||||
echo "Boîtier {$adresse_mac} : " . $verrou['raison'] . " - ignoré pour ce cycle.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$resultat = Lister_archives_en_attente($boitier['Adresse_netbird']);
|
||||
|
||||
if (!$resultat['ok'])
|
||||
@@ -473,6 +485,11 @@ function Executer_cron_archivage()
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Liberer_boitier($verrou['poignee']);
|
||||
}
|
||||
}
|
||||
|
||||
Fermeture_bdd();
|
||||
}
|
||||
|
||||
+20
-2
@@ -4,7 +4,7 @@
|
||||
// (MMSI divergent, ou aucune affectation active - cf synthèse §38-39).
|
||||
// Exécuté manuellement ou via cron, après qu'un administrateur ait mis à jour
|
||||
// les données concernées (TB_Bateaux.MMSI, TB_Affectations_bateaux) :
|
||||
// php /var/www/cron_quarantaine.php
|
||||
// /usr/bin/php /var/www/cron_quarantaine.php
|
||||
//
|
||||
// Ne retente PAS automatiquement : parcourt les fichiers du répertoire de
|
||||
// quarantaine, et pour chacun, relit sa ligne TB_Archives_traitees existante
|
||||
@@ -15,6 +15,10 @@
|
||||
// modifié, nouvelle tentative au prochain lancement.
|
||||
// ============================================================================
|
||||
|
||||
// Même précaution que cron_archivage.php : certains fichiers inclus utilisent des chemins relatifs,
|
||||
// résolus par rapport au répertoire de travail - imprévisible pour une tâche planifiée.
|
||||
chdir("/var/www/html");
|
||||
|
||||
require_once __DIR__ . "/config/config.php";
|
||||
require_once __DIR__ . "/config/fonctions_bdd.php";
|
||||
require_once __DIR__ . "/fonctions_archivage.php";
|
||||
@@ -101,6 +105,16 @@ function Executer_cron_quarantaine()
|
||||
{
|
||||
$chemin = REPERTOIRE_QUARANTAINE . "/" . $nom;
|
||||
|
||||
$adresse_mac = Adresse_mac_depuis_nom($nom);
|
||||
$verrou = Verrouiller_boitier($adresse_mac);
|
||||
if (!$verrou['ok'])
|
||||
{
|
||||
echo " - {$nom} : " . $verrou['raison'] . " - réexamen au prochain passage.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$ligne = Lire_ligne_en_attente($db, $nom);
|
||||
if ($ligne === null)
|
||||
{
|
||||
@@ -108,7 +122,6 @@ function Executer_cron_quarantaine()
|
||||
continue;
|
||||
}
|
||||
|
||||
$adresse_mac = Adresse_mac_depuis_nom($nom);
|
||||
$contenu_chiffre = file_get_contents($chemin);
|
||||
|
||||
$affectation = Resoudre_affectation_active($db, $adresse_mac);
|
||||
@@ -213,6 +226,11 @@ function Executer_cron_quarantaine()
|
||||
unlink($chemin);
|
||||
echo " - {$nom} : quarantaine levée, chargée dans {$nom_base_cible}.\n";
|
||||
}
|
||||
finally
|
||||
{
|
||||
Liberer_boitier($verrou['poignee']);
|
||||
}
|
||||
}
|
||||
|
||||
Fermeture_bdd();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,57 @@ const REPERTOIRE_VERSIONS_SQL = "/home/koriolan/versions/shipheart/ressources/sq
|
||||
const REPERTOIRE_QUARANTAINE = "/home/koriolan/bateaux/archives/quarantaines";
|
||||
const REPERTOIRE_ERREURS = "/home/koriolan/bateaux/archives/erreurs";
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Répertoire des verrous par boîtier (cf Verrouiller_boitier()). Les fichiers
|
||||
// de verrou ne sont JAMAIS supprimés : supprimer un fichier de verrou pendant
|
||||
// qu'un autre processus le détient ouvrirait une fenêtre où deux processus
|
||||
// verrouillent chacun un fichier différent portant le même nom.
|
||||
// ----------------------------------------------------------------------------
|
||||
const REPERTOIRE_VERROUS = "/home/koriolan/bateaux/verrous";
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Verrou exclusif NON bloquant sur un boîtier (adresse MAC), partagé par
|
||||
// cron_archivage.php, cron_quarantaine.php et, plus tard, le traitement à la
|
||||
// demande depuis le portail (synthèse §44.6) : deux traitements simultanés du
|
||||
// même boîtier pourraient sinon créer deux générations ou charger deux fois
|
||||
// dans la même base. Un boîtier déjà verrouillé est simplement sauté, il sera
|
||||
// repris au passage suivant - jamais d'attente.
|
||||
// Le verrou est libéré par Liberer_boitier(), et de toute façon par le
|
||||
// système à la fin du processus (y compris en cas d'arrêt brutal) - aucun
|
||||
// verrou "orphelin" possible, contrairement à un simple fichier témoin.
|
||||
// Renvoie ['ok'=>true, 'poignee'=>resource] ou ['ok'=>false, 'raison'=>string].
|
||||
// ----------------------------------------------------------------------------
|
||||
function Verrouiller_boitier($adresse_mac)
|
||||
{
|
||||
// Nom de fichier construit uniquement à partir des 12 caractères hexadécimaux de l'adresse
|
||||
// (quel que soit son format d'écriture, avec ou sans ':') - jamais de chemin arbitraire :
|
||||
$hex = strtoupper(preg_replace('/[^0-9A-Fa-f]/', '', (string)$adresse_mac));
|
||||
if (strlen($hex) !== 12) return ['ok' => false, 'raison' => "adresse MAC invalide pour un verrou"];
|
||||
|
||||
if (!is_dir(REPERTOIRE_VERROUS) && !@mkdir(REPERTOIRE_VERROUS, 0770, true) && !is_dir(REPERTOIRE_VERROUS))
|
||||
{
|
||||
return ['ok' => false, 'raison' => "répertoire de verrous " . REPERTOIRE_VERROUS . " impossible à créer"];
|
||||
}
|
||||
|
||||
// Mode 'c' : crée le fichier s'il n'existe pas, sans jamais le tronquer.
|
||||
$poignee = @fopen(REPERTOIRE_VERROUS . "/boitier_{$hex}.lock", 'c');
|
||||
if ($poignee === false) return ['ok' => false, 'raison' => "fichier de verrou impossible à ouvrir"];
|
||||
|
||||
if (!flock($poignee, LOCK_EX | LOCK_NB))
|
||||
{
|
||||
fclose($poignee);
|
||||
return ['ok' => false, 'raison' => "déjà en cours de traitement par un autre processus"];
|
||||
}
|
||||
return ['ok' => true, 'poignee' => $poignee];
|
||||
}
|
||||
|
||||
function Liberer_boitier($poignee)
|
||||
{
|
||||
if (!is_resource($poignee)) return;
|
||||
flock($poignee, LOCK_UN);
|
||||
fclose($poignee);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Résout l'affectation active d'un boîtier (par adresse MAC) - cf synthèse
|
||||
|
||||
Reference in New Issue
Block a user