Magento 1.9.1 sendet mehrere E-Mails

7

Ich habe mein Geschäft eingerichtet und bin bereit, damit zu arbeiten. Als ich eine Testbestellung machen werde, habe ich festgestellt, dass Magento die Bestätigungs-E-Mail mehrmals sendet und nicht aufhört zu senden. Ich erhalte die E-Mails zu zweit.

Und ich habe bemerkt, dass eine Ausnahme ausgelöst wird exception.log:

Next exception 'Zend_Db_Statement_Exception' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE (message_id='3')' at line 1, query was: UPDATE `core_email_queue` SET  WHERE (message_id='3')' in /home/newolders/public_html/store/lib/Zend/Db/Statement/Pdo.php:235
Stack trace:
#0 /home/newolders/public_html/store/lib/Varien/Db/Statement/Pdo/Mysql.php(110): Zend_Db_Statement_Pdo->_execute(Array)
#1 /home/newolders/public_html/store/app/code/core/Zend/Db/Statement.php(291): Varien_Db_Statement_Pdo_Mysql->_execute(Array)
#2 /home/newolders/public_html/store/lib/Zend/Db/Adapter/Abstract.php(480): Zend_Db_Statement->execute(Array)
#3 /home/newolders/public_html/store/lib/Zend/Db/Adapter/Pdo/Abstract.php(238): Zend_Db_Adapter_Abstract->query('UPDATE `core_em...', Array)
#4 /home/newolders/public_html/store/lib/Varien/Db/Adapter/Pdo/Mysql.php(428): Zend_Db_Adapter_Pdo_Abstract->query('UPDATE `core_em...', Array)
#5 /home/newolders/public_html/store/lib/Zend/Db/Adapter/Abstract.php(635): Varien_Db_Adapter_Pdo_Mysql->query('UPDATE `core_em...', Array)
#6 /home/newolders/public_html/store/app/code/core/Mage/Core/Model/Resource/Db/Abstract.php(433): Zend_Db_Adapter_Abstract->update('core_email_queu...', Array, 'message_id='3'')
#7 /home/newolders/public_html/store/app/code/core/Mage/Core/Model/Abstract.php(318): Mage_Core_Model_Resource_Db_Abstract->save(Object(Mage_Core_Model_Email_Queue))
#8 /home/newolders/public_html/store/app/code/core/Mage/Core/Model/Email/Queue.php(244): Mage_Core_Model_Abstract->save()
#9 [internal function]: Mage_Core_Model_Email_Queue->send(Object(Mage_Cron_Model_Schedule))
#10 /home/newolders/public_html/store/app/code/core/Mage/Cron/Model/Observer.php(325): call_user_func_array(Array, Array)
#11 /home/newolders/public_html/store/app/code/core/Mage/Cron/Model/Observer.php(72): Mage_Cron_Model_Observer->_processJob(Object(Mage_Cron_Model_Schedule), Object(Mage_Core_Model_Config_Element))
#12 /home/newolders/public_html/store/app/code/core/Mage/Core/Model/App.php(1338): Mage_Cron_Model_Observer->dispatch(Object(Varien_Event_Observer))
#13 /home/newolders/public_html/store/app/code/core/Mage/Core/Model/App.php(1317): Mage_Core_Model_App->_callObserverMethod(Object(Mage_Cron_Model_Observer), 'dispatch', Object(Varien_Event_Observer))
#14 /home/newolders/public_html/store/app/Mage.php(448): Mage_Core_Model_App->dispatchEvent('default', Array)
#15 /home/newolders/public_html/store/cron.php(76): Mage::dispatchEvent('default')
#16 {main}

Könnte mir jemand helfen?

Elias Soares
quelle
Welche Magento-Version verwenden Sie?
Amit Bera
Er antwortete im Titel. Diese Funktion erschien nur in 1.9.1.x
zhartaunik
JA das ist schön! Ich habe das gleiche Problem. Und während das Senden meiner Protokollausgabe als Antwort (weil in einem Kommentar kein ausreichender Platz vorhanden ist) nicht richtig war (von einigen Mods erwähnt), wurde das Bearbeiten der Frage und das Hinzufügen des Protokolls auch von niemandem abgelehnt. so wtf. ist falsch mit dir?! Wieder zeigte das Protokoll an, dass die verarbeiteteAt-Eigenschaft korrekt gefüllt war, aber die Update-Abfrage falsch erstellt wurde. sry aber ich kann dir das log nicht zeigen wegen einiger wirklich gruseliger leute hier. -, - nuff sagte
Manuel Richarz
@ Elias Soares: Läuft die Erweiterung AOE_Scheduler?
Manuel Richarz

Antworten:

2

Ich bin mir nicht sicher, ob Sie in der Zwischenzeit die Lösung gefunden haben, aber ich bin kürzlich auf dem Server eines Clients auf dasselbe Problem gestoßen.

Was passiert ist, war in der Tat dasselbe. Der Cron-Job core_email_queue_send_all hat dieselben E-Mails mehrmals gesendet und jedes Mal wurde dieselbe Ausnahme, die Sie gefunden haben, in das Ausnahmeprotokoll aufgenommen.

Der Cron-Job hat dieselben E-Mails mehrmals gesendet, da das processed_atFeld core_email_queuefür die entsprechenden Nachrichten nicht in der Tabelle gespeichert wurde .

Ich habe dem Code einige Protokolle hinzugefügt und untersucht, wie die Abfrage zum Speichern der core_email_queueNachricht erstellt wurde und warum der SET-Teil davon fehlte (der die zu aktualisierenden Spalten enthalten sollte):

UPDATE `core_email_queue` SET  WHERE (message_id='3')'

In Magento werden vor dem Erstellen der Datenbankabfragen die in der Abfrage verwendeten Spalten mit den Spaltenbeschreibungen für die jeweilige Tabelle innerhalb der Mage_Core_Model_Resource_Abstract::_prepareDataForTableMethode verglichen, indem Folgendes aufgerufen wird:

$fields = $this->_getWriteAdapter()->describeTable($table);

Um die DESCRIBE-Abfrage nicht jedes Mal auszuführen, speichert Magento die DDL-Informationen für die Tabellen zwischen. Innerhalb der Varien_Db_Adapter_Pdo_Mysql::describeTableMethode wird der Cache zuerst überprüft:

public function describeTable($tableName, $schemaName = null)
{
    $cacheKey = $this->_getTableName($tableName, $schemaName);
    $ddl = $this->loadDdlCache($cacheKey, self::DDL_DESCRIBE);
    if ($ddl === false) {
        $ddl = array_map(
            array(
                $this,
                'decorateTableInfo'
            ),
            parent::describeTable($tableName, $schemaName)
        );
        /**
        * Remove bug in some MySQL versions, when int-column without default value is described as:
        * having default empty string value
        */
        $affected = array('tinyint', 'smallint', 'mediumint', 'int', 'bigint');
        foreach ($ddl as $key => $columnData) {
            if (($columnData['DEFAULT'] === '') && (array_search($columnData['DATA_TYPE'], $affected) !== FALSE)) {
                $ddl[$key]['DEFAULT'] = null;
            }
        }
        $this->saveDdlCache($cacheKey, self::DDL_DESCRIBE, $ddl);
    }

    return $ddl;
}

Ich fand , dass die Spalten aus dem Cache für die empfangene core_email_queueTabelle, waren nicht die , die erwartet, statt sie manchmal waren: data, lifetime, expireund priority.

Dies deutete auf ein Cache-Problem hin und ich stellte fest, dass Zend_Cache_CoreDaten in den DDL-Cache-Dateien gespeichert wurden, manchmal durch Zend_Cache_Backend_File::save()direkten Aufruf und manchmal durch Aufruf Zend_Cache_Backend_TwoLevels::save().

Der Cache mit zwei Ebenen von Zend verwendet die _prepareDataMethode, um ein serialisiertes Array zum Speichern der Daten- und Metadateninformationen zu erstellen:

private function _prepareData($data, $lifetime, $priority)
{
    $lt = $lifetime;
    if ($lt === null) {
        $lt = 9999999999;
    }
    return serialize(array(
        'data' => $data,
        'lifetime' => $lifetime,
        'expire' => time() + $lt,
        'priority' => $priority
    ));
}

Schließlich bestand das Problem darin, dass der Cron (der die E-Mails gesendet hat) über die Befehlszeile aufgerufen wurde. Beim Vergleich einer Anforderung vom Browser mit einer Befehlszeilenanforderung stellte ich fest, dass Mage_Core_Model_Cache::getBackendOptionsverschiedene Optionen zurückgegeben wurden. Dieser Server wurde für die Verwendung des APC-Cache eingerichtet, war jedoch bei Ausführung des Cron ini_get(‘apc.enabled’)falsch.

Auf diesem Server gab es 2 PHP - Konfigurationsdateien FPM / php.ini wo apc.enabled war 1 , und cli / php.ini wo apc.enabled war 0 . Die Magento-Instanz, die über die Befehlszeile ausgeführt wurde, konnte daher den APC-Cache nicht verwenden, sodass kein zweistufiger Cache verwendet wurde, was dazu führte, dass sie nicht wusste, wie die Daten aus den Cache-Dateien korrekt gelesen werden sollten.

Die FPM Magento Instanz verwendet APC und die beiden Level - Cache und spart DDL Daten in die var / cache Ordner in einem Array mit den beigefügten data, lifetime, expireund priorityTasten. Wenn die cron ran und die DDL - Cache - Datei lesen, verwendet es die Daten dort gefunden und im Grunde für jede Tabelle in Betracht gezogen, dass die Spalten sind data, lifetime, expireund priority.

Das Ändern von apc.enabled in der Konfigurationsdatei cli / php.ini auf 1 hat den Trick ausgeführt und das Problem behoben.

Wenn Sie mehr darüber erfahren möchten, wie ich dieses Problem behoben habe, können Sie sich die detailliertere Erklärung ansehen, die ich für einen Blog-Beitrag geschrieben habe: http://ayg.ro/magento-cron-twolevel-cache-issue-pdoexception- sqlstate-42s22-and-sqlstate-42000

Marina Vilcea
quelle
Ich habe das auf eine andere Weise gelöst, an die ich mich nicht mehr erinnere. ABER Ihre Lösung ist sehr gut erklärt und für mich sinnvoll, daher werde ich sie als richtige Antwort markieren, da dies vielen Menschen mit ähnlichen Problemen helfen kann!
Elias Soares
4

Dieses Problem muss mit dem neuen Magento Email Queue-System zusammenhängen, das verwaiste Datensätze in der Empfängertabelle hinterlässt. Wenn dies Ihr Problem ist, sende ich Ihnen einen Fix.

Das neue Magento Email Queue-System verwaltet diese beiden Tabellen: core_email_queue und core_email_queue_recipients . Ersteres behandelt die E-Mail-Nachrichten und letzteres die Empfänger dieser Nachrichten.

Die Tabelle core_email_queue wird bereinigt, wenn E-Mails in der Magento-E-Mail-Warteschlange gesendet werden. Diese Bereinigung wird von einem Cron-Tab-Job namens core_email_queue_clean_up durchgeführt , der in der Konfigurationsdatei app / code / core / Mage / Core / etc / config.xm l definiert ist. Der Code, der die Bereinigung durchführt, wird in der Funktion removeSentMessages in der Klasse Mage_Core_Model_Resource_Email_Queue definiert :

/**
 * Remove already sent messages
 *
 * @return Mage_Core_Model_Resource_Email_Queue
 */
public function removeSentMessages()
{
    $this->_getWriteAdapter()->delete($this->getMainTable(), 'processed_at IS NOT NULL');
    return $this;
}

Der obige Code wird einmal täglich von der Cron-Task ausgeführt.

Aber es kommt vor, dass die core_email_queue_recipients Tabelle (die, die E - Mail - Empfänger hält, und die mit der verbunden ist core_email_queue durch die Tabelle message_id Feld), nicht zusammen mit der gereinigt core_email_queue Tabelle (die, die E - Mail - Nachrichten hält), so dass verwaiste Aufzeichnungen innen Diese Empfängertabelle, wenn dann die Nachrichtentabelle bereinigt wird.

Das hier beschriebene Problem tritt auf, wenn die Tabelle core_email_queue (Messages) zurückgesetzt wird und das Feld message_id für die automatische Inkrementierung in dieser Tabelle erneut auf 1 gesetzt wird.

Da die Tabelle core_email_queue_recipients (Empfänger) nicht entsprechend bereinigt wurde, werden beim Hinzufügen neuer E-Mails zur Magento-E-Mail-Warteschlange neue Datensätze in der Tabelle core_email_queue erstellt (wobei message_id ab 1 erneut beginnt) und gleichzeitig neue Datensätze erstellt in der Tabelle core_email_queue_recipients mit denselben IDs (beginnend erneut mit 1).

Das Problem ist, dass diese IDs möglicherweise bereits als Waiseneinträge in der Empfängertabelle vorhanden sind (aufgrund früherer E-Mail-Nachrichten). Diese neuen Nachrichten-IDs werden dann in der Tabelle core_email_queue_recipients wiederholt . Am Ende werden verschiedene E-Mail-Nachrichten durch die message_id mit ihren entsprechenden Empfängern verknüpft , aber sie werden auch fälschlicherweise mit früheren Empfängern verknüpft, denen dieselbe message_id aus früheren E-Mails zugewiesen wurde .

Wenn also Empfänger gesucht werden, um eine bestimmte Nachricht zu senden, können neben dem entsprechenden Empfänger andere falsche Empfänger auftreten.

Glücklicherweise ist die Behebung dieses Problems einfach durchzuführen.

Sie müssen lediglich alle IDs für wiederholte Nachrichten in der Tabelle core_email_queue_recipients bereinigen und sicherstellen, dass beim Löschen einer Nachricht in der Tabelle core_email_queue gleichzeitig die entsprechenden Empfänger in der Tabelle core_email_queue_recipients gelöscht werden.

Der beste Weg, dies zu erreichen, besteht darin, einen Fremdschlüssel zu erstellen, der diese Datensätze verknüpft und in der Kaskade löscht (Sie müssen jedoch einige Bereinigungen vornehmen, bevor Sie dies tun können).

Dies ist das Verfahren, um das Problem zu beheben:

1) Führen Sie die folgenden zwei SQL-Abfragen aus, um die Tabelle core_email_queue_recipients von verwaisten Datensätzen und IDs für wiederholte Nachrichten zu entfernen:

DELETE FROM core_email_queue_recipients WHERE message_id NOT IN (SELECT message_id FROM core_email_queue);
DELETE FROM core_email_queue_recipients WHERE recipient_id < (SELECT recipient_id FROM (SELECT recipient_id FROM core_email_queue_recipients ORDER BY message_id ASC, recipient_id DESC LIMIT 1) AS r);

Die erste Abfrage löscht verwaiste Datensätze und die zweite löscht alte Datensätze, die nicht mehr gültig sind.

2) Erstellen Sie einen Fremdschlüssel in der Tabelle core_email_queue_recipients , um die Empfängerdatensätze in der Kaskade zu löschen. Die SQL-Abfrage zum Erstellen dieses Fremdschlüssels lautet:

ALTER TABLE core_email_queue_recipients ADD FOREIGN KEY(message_id) REFERENCES core_email_queue(message_id) ON DELETE CASCADE;

Wenn Sie diesen neuen Fremdschlüssel verwenden, bleiben beim Bereinigen der Tabelle core_email_queue_recipients keine verwaisten Datensätze in der Tabelle core_email_queue_recipients übrig , und in Zukunft werden keine doppelten Nachrichten an falsche Empfänger gesendet.

César Revert-Gomar
quelle
1

Wie Sie Ihre Anfrage sehen können

UPDATE `core_email_queue` SET  WHERE (message_id='3')'

hat nicht was zu setzen. Ich denke, hier versucht Magento, einen Status festzulegen, dessen Sinn "bereits gesendeter Brief" ist. Ich bin nicht sicher, vielleicht Feld aktualisierenprocessed_at

upd.1

Es sieht so aus, als ob die Idee richtig war. Vor dem Speichern haben wir Folgendes (Mage / Core / Model / Email / Queue.php (244)):

$message->setProcessedAt(Varien_Date::formatDate(true));

Könnten Sie danach

Mage::log(Varien_Date::formatDate(true));
Mage::log($message->getData());

Und zeig uns Ergebnis.

upd.2

Ich habe das beschriebene Problem nicht reproduziert. ich habe

Ubuntu 14.04.2 LTS

Nginx-Version: Nginx / 1.4.6 (Ubuntu)

PHP Version 5.5.9-1ubuntu4.9

MySQL Server Version 5.6.19

Magento ver. 1.9.1.0

Was ist deine Konfiguration?

zhartaunik
quelle
Ja, aber ich kann nicht finden, wo es im Magento-Code behoben werden kann ...: /
Elias Soares
Ich schaue es mir an. Können Sie in Ihrem ersten Beitrag einige Schritte angeben, wie Sie diese Funktion aktivieren können, damit einige Zeilen in dieser Tabelle angezeigt werden? Oder zeigen Sie uns diese Tabelle
zhartaunik
Warten auf Details von Ihnen
zhartaunik
Nur die Neuinstallation von Magento 1.9.1 und der Fehler tritt auf. Wenn Sie eine Beispielbestellung aufgeben, tritt das Problem auf, wenn versucht wird, die Bestellbestätigungsmail zu senden.
Elias Soares
1
wie im obigen Kommentar erwähnt: processAt wurde korrekt eingestellt. Ich habe versucht, tiefer zu graben und festgestellt, dass manchmal : $ this -> _ getWriteAdapter () -> descriptionTable ($ table); führt zu einer falschen Tabellenbeschreibung. Es werden nicht die Spalten von email_queue zurückgegeben. Es gibt Spalten wie diese zurück: Daten, Lebensdauer, Ablaufdatum, Priorität Und manchmal die richtigen Spalten: Nachrichten-ID, Entitäts-ID, Entitätstyp, Nachrichtenkörper, ..., verarbeitet_at
Manuel Richarz