Magento 1.9.1で複数のメールを送信する


7

私は自分の店をセットアップし、それを使用する準備ができています。テスト注文をするとき、Magentoが確認メールを複数回送信していて、送信が停止していないことに気付きました。メールが2つずつ届きます。

そして、私は例外がスローされていることに気づきました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}

誰か助けてもらえますか?


どのmagentoバージョンを使用していますか?
アミットベラ

彼はタイトルで答えた。この機能は1.9.1.xでのみ表示されました
zhartaunik

いいね!私は同じ問題を抱えています。そして、私のコメント出力を回答として送信している間(コメントにエノスペースがないため)は正しくありません(いくつかのmodで言及されています)が、質問を編集してログを追加することも誰も拒否されました。そうwtf。あなたは間違っていますか?再度、ログには、processedAt-Propertyが正しく入力されたが、更新クエリが正しく構築されなかったことが表示されました 申し訳ありませんが、このあたりには本当に気味悪い人がいるため、ログを表示できません。-、-
nuff

@エリアス・ソアレス:AOE_Scheduler拡張機能を実行していますか?
Manuel Richarz

回答:


2

その間に解決策が見つかるかどうかはわかりませんが、最近クライアントのサーバーで同じ問題が発生しました。

実際に起こったことは同じで、cronジョブcore_email_queue_send_allが同じメールを複数回送信し、そのたびに、見つかった同じ例外が例外ログに追加されていました。

processed_atフィールドがcore_email_queue対応するメッセージのテーブルに保存されなかったため、cronジョブは同じメールを複数回送信していました。

コードにいくつかのログを追加し、core_email_queueメッセージを保存するためのクエリがどのように作成されたか、なぜメッセージのSET部分が欠落していたのか(更新する列が含まれているはずです)を調べました。

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

Magentoでは、データベースクエリを作成する前に、クエリで使用される列が、次のMage_Core_Model_Resource_Abstract::_prepareDataForTable呼び出しによってメソッド内のそれぞれのテーブルの列の説明と照合されます。

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

毎回DESCRIBEクエリを実行しないために、MagentoはテーブルのDDL情報をキャッシュします。Varien_Db_Adapter_Pdo_Mysql::describeTableメソッド内では、まずキャッシュがチェックされます。

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;
}

私は列がためにキャッシュから受信したことがわかったcore_email_queue代わりに、時には彼らがいた、テーブル期待するものではありませんでした:datalifetimeexpirepriority

これはキャッシュの問題を指摘し、Zend_Cache_CoreデータをDDLキャッシュファイルに保存するときに、Zend_Cache_Backend_File::save()直接呼び出したり、呼び出したりしたことがわかりましたZend_Cache_Backend_TwoLevels::save()

Zendの2つのレベルのキャッシュは、この_prepareDataメソッドを使用してシリアル化された配列を構築し、データとメタデータ情報を格納します。

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
    ));
}

最後に、問題は電子メールを送信したcronがコマンドラインから呼び出されたことです。ブラウザからのリクエストとコマンドラインリクエストを比較すると、Mage_Core_Model_Cache::getBackendOptions異なるオプションを返すことがわかりました。このサーバーはAPCキャッシュを使用するように設定されていましたini_get(‘apc.enabled’)が、cronが実行されていたときはfalseでした。

このサーバ上の2つのPHPの設定ファイルがありましたFPM / php.iniの場所apc.enabledをはいた1、およびCLI / php.iniの場所apc.enabledをした0。コマンドラインから実行されたMagentoインスタンスはAPCキャッシュを使用できなかったため、2レベルのキャッシュを使用しなかったため、キャッシュファイルからデータを正しく読み取る方法がわかりませんでした。

FPM Magentoのインスタンスは、APCと2つのレベルのキャッシュを使用し、DDLにデータを保存したVAR /キャッシュフォルダを持つ配列で囲まれdatalifetimeexpireおよびpriorityキー。ときにcron RANおよびDDLキャッシュファイルを読み込み、そのデータを使用が発見し、基本的には各テーブルに考慮、列があることをdatalifetimeexpirepriority

cli / php.ini設定ファイルでapc.enabled1に変更すると、トリックが発生して問題が解決しました。

この問題のデバッグ方法の詳細に興味がある場合は、ブログ投稿のために書いた詳細な説明をご覧ください。http//ayg.ro/magento-cron-twolevel-cache-issue-pdoexception- sqlstate-42s22-and-sqlstate-42000


私はこれをもう思い出さない別の方法で解決しました。しかし、あなたの解決策は非常によく説明されており、私には理にかなっているので、同様の問題を抱えている多くの人々に役立つ可能性があるため、正解としてマークします。
エリアスソアレス2016

4

この問題は、受信者テーブルに孤立したレコードを残す新しいMagento Email Queueシステムに関連している必要があります。これがあなたの問題である場合、私はあなたに修正を送ります。

新しいMagento Email Queueシステムは、これら2つのテーブル、core_email_queueおよびcore_email_queue_recipientsを管理します。前者は電子メールメッセージを処理し、後者はこれらのメッセージの受信者を処理します。

core_email_queue Magentoのメールキューに電子メールが送信されるように、テーブルが一掃されます。このクリーニングは、app / code / core / Mage / Core / etc / config.xm l configファイル内で定義されているcore_email_queue_clean_upと呼ばれるcron タブジョブによって実行されます。クリーニングを実行するコードは、Mage_Core_Model_Resource_Email_QueueクラスのremoveSentMessages関数で定義されてます。

/**
 * 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;
}

上記のコードは、cronタスクによって1日に1回実行されます。

しかし、core_email_queue_recipientsテーブル(電子メールの受信者を保持し、message_idフィールドによってcore_email_queueテーブルにリンクされているテーブル)は、core_email_queueテーブル(電子メールメッセージを保持するテーブル)と一緒にクリーンアップされず、内部に孤立したレコードが残るメッセージテーブルがクリーンアップされるときに、その受信者テーブル。

ここで説明する問題は、core_email_queueテーブル(メッセージ)がリセットされ、このテーブルの自動インクリメントmessage_idフィールドが1に再初期化されるときに発生します。

core_email_queue_recipientsテーブル(Recipients)はそれに応じてクリーンアップされていないため、新しい電子メールがMagento Email Queueに追加されると、core_email_queueテーブルに新しいレコードが作成され(message_idが1から再び開始されます)、同時に新しいレコードが作成されます上core_email_queue_recipientsのこれらの同じIDを持つテーブル(1から再度開始します)。

問題は、これらのIDが(以前の電子メールメッセージが原因で)孤立レコードとしてRecipientsテーブルにすでに存在している可能性があることです。これらの新しいメッセージIDは、core_email_queue_recipientsテーブル内で繰り返されます。結局、異なるメールメッセージがmessage_idによって対応する受信者にリンクされますが、以前のメールから同じmessage_idが割り当てられた以前の受信者に誤ってリンクされます。

したがって、特定のメッセージを送信するために受信者を検索すると、適切な受信者以外に、他の誤った受信者が発生する可能性があります。

幸い、この問題の修正は簡単に実行できます。

必要なのは、core_email_queue_recipientsテーブルで繰り返されるすべてのメッセージIDを消去し、core_email_queueテーブルでメッセージが削除されるときに、対応する受信者がcore_email_queue_recipientsテーブルで削除されることを確認することです。

これを実現する最良の方法は、これらのレコードをリンクしてカスケードで削除する外部キーを作成することです(ただし、これを行うには、いくつかのクリーンアップを行う必要があります)。

これは問題を修正する手順です:

1)次の2つのSQLクエリを実行して、孤立したレコードと繰り返されるメッセージIDからcore_email_queue_recipientsテーブルを削除します。

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);

最初のクエリは孤立したレコードを削除し、2番目のクエリは有効でなくなった古いレコードを削除します。

2)core_email_queue_recipientsテーブルに外部キーを作成して、カスケードでRecipientsレコードを削除します。この外部キーを作成するSQLクエリは次のとおりです。

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

この新しい外部キーを使用することにより、core_email_queueテーブルをクリーンアップするときに、孤立したレコードがcore_email_queue_recipientsテーブルに残らず、間違った受信者に重複したメッセージが送信されることはありません。


1

あなたのクエリを見ることができるように

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

設定するものがありません。ここでは、magentoが「文字がすでに送信されている」という意味のステータスを設定しようとしていると思います。よくわかりません。フィールドを更新してくださいprocessed_at

upd.1

アイデアは正しかったようです。保存する前に、次のようにします(Mage / Core / Model / Email / Queue.php(244)):

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

この後できますか

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

そして結果を見せてください。

upd.2

説明した問題を再現しませんでした。私が持っています

Ubuntu 14.04.2 LTS

nginxバージョン:nginx / 1.4.6(Ubuntu)

PHPバージョン5.5.9-1ubuntu4.9

MySQLサーバーバージョン5.6.19

マジェントver。1.9.1.0

あなたの設定は何ですか?


はい、しかし、私はmagentoコードのどこでそれを修正するのかわかりません...:/
エリアス・ソアレス

私はそれを見ています。最初の投稿に、この機能を有効にしてこのテーブルにいくつかの行を表示させる方法をいくつか含めることができますか?または、このテーブルを見せてください
zhartaunik 2015

あなたからの詳細を待っています
zhartaunik 2015

Magento 1.9.1の新規インストールとエラーが発生します。注文例を作成すると、注文確認メールを送信しようとすると問題が発生します。
エリアスソアレス

1
上記のコメントで述べたように、processedAtは正しく設定されました。私はより深く掘ろうとしましたが、時々それが見つかりました:$ this-> _ getWriteAdapter()-> describeTable($ table); テーブルの説明が間違っています。email_queueの列は返しません。次のような列を返します:data、lifetime、expire、priorityそして時には正しい列:message_id、entity_id、entity_type、message_body、...、processed_at
Manuel Richarz
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.