Vous n'êtes pas identifié(e).
[25 janvier 2021] - Publication de Wanewsletter 3.1.0
Voila je fait de l'envoi de mass (+500 000) ça marche mais .. j'ai fait des gros trou dans ton code et j'aimerais corriger ces trous.
Voila principalement ou j'ai un problème :
abo_id IN(" . implode(', ', $abo_ids) . ")
Comme tu dois t'en douter avec 500 000mails envoyer j'atomise la requete sql, la liste étant bien trop grande
Je connais encore mal tout ton code, comme solution je ne vois que l'insertion dans une table temporaire des liste abo_id.
Voila si tu as un conseil je suis preneur
ps : il y a un raison particulière pour avoir passé par fichier et non pas une table ?
ps2 : tu travails avec les fichiers lockfile dans engine_send.php, et envoi.php, il y a d'autres ?
Hors ligne
Voila les modifications que j'ai apporté afin de garder les possibilités du script et de dépaser le cap de 40 000mails par envoir.
Voila je passe tout l'état des envois en base (question de gout) et procede de façon recurcive pour les mises à jours des états, c'est plus long en therme d'execution mais sans limites au moins.
( ATTENTION je ne suis pas un grand dev, loin de la, j'ai testé chez moi ça marche sans bug, mais c'est pas 100% sur, d'ailleur je suis ouvert à tout commantaire )
(Record à 512 867)
Éditez le fichier admin/envoi.php (ligne 236~)
foreach( $liste_ids as $liste_id )
{
$lockfile = sprintf(WA_LOCKFILE, $liste_id);
if( file_exists($lockfile) && filesize($lockfile) > 0 )
{
$fp = fopen($lockfile, 'r+');
if( flock($fp, LOCK_EX|LOCK_NB) )
{
$abo_ids = fread($fp, filesize($lockfile));
$abo_ids = array_map('trim', explode("\n", trim($abo_ids)));
if( count($abo_ids) > 0 )
{
$abo_ids = array_unique(array_map('intval', $abo_ids));
$sql = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
AND liste_id = " . $liste_id;
if( !$db->query($sql) )
{
trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
}
}
ftruncate($fp, 0);
flock($fp, LOCK_UN);
}
fclose($fp);
}
}
En
foreach( $liste_ids as $liste_id )
{
$table_lockfile = "locktable".$liste_id;
$sql = "SELECT count(*) FROM ".$table_lockfile.";";
if($result = $db->query($sql))
{
$row = $result->fetch();
$count = $row["count(*)"];
if($count > 0)
{
$sql = "SELECT id_email
FROM ".$table_lockfile.";";
if( !($result = $db->query($sql)) )
{
trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
}
while( $row = $result->fetch() )
{
$sql2 = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id = '".$row['id_email']."'
AND liste_id = '" . $liste_id."'";
if( !$db->query($sql2) )
{
trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
}
}
$sql = "TRUNCATE TABLE `".$table_lockfile."`;";
$result = $db->query($sql);
}
}
}
Éditez le fichier include/engine_send.php (ligne 50~)
$lockfile = sprintf(WA_LOCKFILE, $listdata['liste_id']);
if( file_exists($lockfile) )
{
$isBeginning = false;
$fp = fopen($lockfile, 'r+');
$supp_address = array();// On en tient pas compte, ça l'a déjà été lors du premier flôt
}
else
{
$isBeginning = true;
$fp = fopen($lockfile, 'w');
@chmod($lockfile, 0600);
}
if( !flock($fp, LOCK_EX|LOCK_NB) )
{
fclose($fp);
return $lang['Message']['List_is_busy'];
}
if( filesize($lockfile) > 0 )
{
//
// L'envoi a planté au cours d'un "flôt" précédent. On récupère les éventuels
// identifiants d'abonnés stockés dans le fichier lock et on met à jour la table
//
$abo_ids = fread($fp, filesize($lockfile));
$abo_ids = array_map('trim', explode("\n", trim($abo_ids)));
if( count($abo_ids) > 0 )
{
$abo_ids = array_unique(array_map('intval', $abo_ids));
$sql = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
AND liste_id = " . $listdata['liste_id'];
if( !$db->query($sql) )
{
trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
}
}
ftruncate($fp, 0);
fseek($fp, 0);
}
EN
$table_lockfile = "locktable".$listdata['liste_id'];
$sql = "SELECT count(*) FROM ".$table_lockfile.";";
if($result = $db->query($sql))
{
$isBeginning = false;
$supp_address = array();// On en tient pas compte, ça l'a déjà été lors du premier flôt
}else
{
$isBeginning = true;
$sql = "CREATE TABLE `".$table_lockfile."` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
`id_email` VARCHAR( 100 ) NOT NULL ,
PRIMARY KEY ( `id` )
);";
$result = $db->query($sql);
$count = 0;
}
if($count > 0)
{
//
// L'envoi a planté au cours d'un "flôt" précédent. On récupère les éventuels
// identifiants d'abonnés stockés dans le fichier lock et on met à jour la table
//
$sql = "SELECT id_email
FROM ".$table_lockfile.";";
if( !($result = $db->query($sql)) )
{
trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
}
while( $row = $result->fetch() )
{
$sql2 = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id = '".$row['id_email']."'
AND liste_id = '" .$listdata['liste_id']."'";
if( !$db->query($sql2) )
{
trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
}
}
$sql = "TRUNCATE TABLE `".$table_lockfile."`;";
$result = $db->query($sql);
}
Éditez le fichier include/engine_send.php (ligne 356~)
fwrite($fp, implode("\n", $abo_ids[FORMAT_TEXTE])."\n");
EN
$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$abo_ids[FORMAT_TEXTE]."');";
$result2 = $db->query($sql2);
Éditez le fichier include/engine_send.php (ligne 378~)
fwrite($fp, implode("\n", $abo_ids[FORMAT_HTML])."\n");
EN
$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$abo_ids[FORMAT_TEXTE]."');";
$result2 = $db->query($sql2);
Éditez le fichier include/engine_send.php (ligne 555~)
fwrite($fp, "$row[abo_id]\n");
EN
$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$row['abo_id']."');";
$result2 = $db->query($sql2);
Éditez le fichier include/engine_send.php (ligne 631~)
if( count($abo_ids) > 0 )
{
$sql = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
AND liste_id = " . $listdata['liste_id'];
if( !$db->query($sql) )
{
trigger_error('Impossible de mettre à jour la table des abonnés (connexion au serveur sql perdue)', ERROR);
}
}
EN
if( count($abo_ids) > 0 )
{
$sql = "SELECT id_email
FROM ".$table_lockfile.";";
if( !($result = $db->query($sql)) )
{
trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
}
while( $row = $result->fetch() )
{
$sql2 = "UPDATE " . ABO_LISTE_TABLE . "
SET send = 1
WHERE abo_id = '".$row['id_email']."'
AND liste_id = '" .$listdata['liste_id']."'";
if( !$db->query($sql2) )
{
trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
}
}
}
Éditez le fichier include/engine_send.php (ligne 579~)
flock($fp, LOCK_UN);
fclose($fp);
unlink($lockfile);
EN
$sql = "DROP TABLE `".$table_lockfile."`;";
$result = $db->query($sql);
Éditez le fichier include/engine_send.php (ligne 668~)
ftruncate($fp, 0);
flock($fp, LOCK_UN);
fclose($fp);
EN
$sql = "TRUNCATE TABLE `".$table_lockfile."`;";
$result = $db->query($sql);
Éditez le fichier include/engine_send.php (ligne 684~)
unlink($lockfile);
EN
$sql = "DROP TABLE `".$table_lockfile."`;";
$result = $db->query($sql);
Hors ligne
ps : il y a un raison particulière pour avoir passé par fichier et non pas une table ?
Oui, j'ai jugé insensé d'envoyer, pour reprendre ton cas, 500000 requêtes SQL dans la tronche du serveur de base de données. :-)
ps2 : tu travails avec les fichiers lockfile dans engine_send.php, et envoi.php, il y a d'autres ?
Non, que dans ces deux fichiers.
Pourquoi ne fais-tu pas tes envois par flot. En faisant tes envois par flot de 40000 par exemple.
Ou utilise le script contrib/wanewsletter pour faire tes envois en ligne de commande et utilise l'option --limit=40000 pour que le script n'envoie que 40000 emails (ce qui limite du même coup la taille de la requête sql).
PHP et MySQL, un duo gagnant !
Hors ligne
j'utilse "contrib/wanewsletter" bien entendu ^^ et l'option limit, les 460 000 autres mails je fait comment pour les envoyer ?
ps : ben pour etre franc mes process mysql ne depase pas 40% en resources sur l'envoi de 500 000 donc bof ça dérange pas plus que ça.
Hors ligne
Cette approche de gestion du Lock dans une table me plait car elle pourrait permettre d'apporter plus de souplesse (en particulier dans le cadre d'envoi de plusieurs mails à la même liste me semble-t-il!) et d'homogénéité à WNL (tout est géré en BD).
Question consommation de CPU, il me semble que la requête de mise à jour de la table "ABO_LISTE_TABLE" doit grandement améliorier les performances car elle est effectuée à travers la valeur de Index ("WHERE abo_id = '".$row['id_email']."'AND liste_id = '" . $liste_id."'") et non à travers le parcours de l'Index/table (WHERE abo_id IN(" . implode(', ', $abo_ids) . ") AND liste_id = " . $listdata['liste_id']).
Je vote donc pour que Bobe la prenne en compte dans une prochaine version si cela est possible.
NB: Sur certain moteur de BD, l'utilisation d'une fonction sur la valeur de l'occurrence à rechercher désactive l'utilisation de(s) l'Index.
Hors ligne
En mode : 1 abonnée = 1 mail
J'ai fait un premier essai sur une liste de 30 000 abonnées et je n'ai eu aucun soucis.
Je viens de faire un essai sur une liste de 85 000 abonnées et la ça bloque à peut prêt tous les 5 000 mails envoyés … En cours d'envoie d'ai testé un changement de mode et j'ai eu le message d'erreur suivant à la reprise de l'envoie : « L'email n'a pu être envoyé ! Fichier : engine_send.php Ligne : 375 »
Je pense que ses modifications sont intéressantes mais je ne préfère pas prendre le risque d'essayer … Je préfère attendre une version qui gère mieux les mailings « important ».
Hors ligne