У меня возникла проблема, когда я считаю, что процесс повторной индексации цены продукта вызывает исключение тупиковой ситуации в процессе оформления заказа.
Я поймал это исключение в процессе оформления заказа:
Исключение преобразования заказа: SQLSTATE [40001]: ошибка сериализации: 1213 Обнаружена тупиковая ситуация при попытке получить блокировку; попробуйте перезапустить транзакцию
К сожалению, у меня нет полной трассировки стека из-за того, где было обнаружено исключение, но, проверяя состояние INNODB, я смог отследить тупик:
SELECT `si`.*, `p`.`type_id` FROM `cataloginventory_stock_item` AS `si`
INNER JOIN `catalog_product_entity` AS `p` ON p.entity_id=si.product_id
WHERE (stock_id=1)
AND (product_id IN(47447, 56678)) FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 329624 n bits 352 index
`PRIMARY` of table `xxxx`.`catalog_product_entity`
SQL запрашивающая блокировка таблицы в конечном итоге генерируется, Mage_CatalogInventory_Model_Stock::registerProductsSale()
когда он пытается получить текущий инвентарный счет, чтобы уменьшить его.
В то время, когда возникла взаимоблокировка, выполнялся процесс переиндексации цены продукта, и я предполагаю, что на нем была блокировка чтения, catalog_product_entity table
которая вызвала взаимоблокировку. Если я правильно понимаю взаимоблокировку, любая блокировка чтения вызовет взаимоблокировку, но переиндексация цены продукта удерживает блокировку в течение справедливого времени, так как на сайте около 50 000 товаров.
К сожалению, к этому моменту в потоке кода проверки была снята оплата с кредитной карты клиента (через пользовательский модуль оплаты), и создание соответствующего объекта заказа не удалось.
Мои вопросы:
- Является ли логика пользовательского платежного модуля неисправной? т.е. есть ли принятый поток для гарантии того, что Magento может преобразовать квоту в исключение заказа бесплатно до совершения платежа в способ оплаты (кредитная карта)?
Редактировать: Похоже, логика платежного модуля действительно неверна, так как вызов $ paymentmethod-> authorize () должен произойти после того места, где возникает этот тупик, а не до (согласно ответу Ивана ниже). Тем не менее, транзакция по-прежнему блокируется тупиком (хотя и без ошибочного списания средств с кредитной карты).
Вызов этой функции
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
вMage_CatalogInventory_Model_Stock::registerProductsSale()
делает его блокировки чтения, насколько опасно было бы сделать это без блокировки чтения?При поиске ответа в сети несколько мест предложили не проводить полную переиндексацию, пока сайт горячий; вряд ли кажется хорошим решением; Является ли проблема индексации, вызывающая взаимные блокировки таблиц и конфликты блокировок, известной проблемой в Magento, есть ли обходные пути?
Редактировать: Кажется, что оставшийся вопрос здесь является вопросом от третьего вопроса; переиндексация, вызывающая взаимные блокировки таблиц. Нужны обходные пути для этого.
Изменить: концепция, что взаимоблокировки не сами по себе проблемы, а ответ на них должны быть в центре внимания, имеет большой смысл. Дальнейшее расследование, чтобы найти точку в коде, чтобы перехватить исключение взаимоблокировки и повторить запрос. Выполнение этого на уровне адаптера Zend Framework DB является одним из подходов, но я также ищу способ сделать это в коде Magento для упрощения сопровождения.
В этой теме есть интересный патч: http://www.magentocommerce.com/boards/viewthread/31666/P0/, который, кажется, решает соответствующее условие взаимоблокировки (но не этот конкретно).
Изменить: Очевидно, блокировка была решена до определенной степени в CE 1.8 Альфа. Все еще ищу обходной путь, пока эта версия не выходит из альфы
Ответы:
Существует довольно большая вероятность того, что ваш метод оплаты обрабатывает платеж неправильно.
Magento Order Save Процесс довольно прост:
checkout_type_onepage_save_order
иsales_model_service_quote_submit_before
Mage_CatalogInventory_Model_Stock::registerProductsSale()
вызывается на этом событии наблюдателя$order->place()
метод, который обрабатывает платеж, вызвав его$paymentMethod->authorize()
,$paymentMethod->capture()
или$paymentMethod->initialize()
зависит от его логики.sales_flat_order_*
.Таким образом, как вы видите, такой способ оплаты не может быть платным до блокировки инвентаря и считывания цен на продукт или информации о продукте.
Это возможно только в том случае, если способ оплаты реализован таким образом, что он сам выполняет загрузку продуктов с ценами после выполнения вызова API для операции начисления платы.
Надеюсь, что это поможет вам в отладке вашей проблемы.
Что касается переиндексации, это должно быть безопасно, если у вас нет этой проблемы с методом оплаты. Поскольку операции чтения, которые зависят от блокировок, выполняются до того, как деньги будут списаны.
источник
registerProductsSale()
(понимая, что с исправлениями в модуле пользовательских платежей будет устранена проблема с зарядкой карты клиента).Поскольку это пользовательское расширение, мы можем найти собственный обходной путь (читай: взломать), чтобы повторить попытку сохранения без редактирования основных файлов.
Я решил все мои тупиковые проблемы с помощью следующих двух методов, добавленных в вспомогательный класс. Вместо звонка
$product->save()
я сейчас звонюMage::helper('mymodule')->saferSave($product)
:Это выполняет две разные вещи - он ставит повторную попытку в очередь при обнаружении тупика и устанавливает экспоненциально увеличивающееся время ожидания для этой повторной попытки. Он также устанавливает уровень изоляции транзакции. Существует много информации о SO и DBA.SE для получения дополнительной информации об уровнях изоляции транзакций MySQL.
FWIW, я не сталкивался с тупиком с тех пор.
источник
$tries
к этой функцииsleep($this->getDelay());
На форумах Magento говорят о редактировании файла библиотеки Zend: lib / Zend / Db / Statement / Pdo.php
Оригинальная функция _execute:
После модификации:
Как вы можете видеть, единственное, что было изменено, это то, что $ try был перемещен за пределы цикла.
Как всегда, предлагается попробовать это в среде разработки / тестирования, а не мгновенно развертывать это исправление в производственной среде.
источник
У меня есть такая же проблема на сайте Magento 1.11, и у меня есть открытый билет с Magento на нем с 12.11.2012. Они подтвердили, что это проблема, и предположительно создают патч.
Мой вопрос: почему в это время нужно переиндексировать цену? Я не думаю, что это необходимо:
источник
У нас была похожая тупиковая проблема, когда во время переиндексации были сделаны определенные звонки. Для нас это проявилось, в основном, когда покупатель будет что-то добавлять в корзину. Хотя, вероятно, не удалось устранить реальную проблему, реализация асинхронной переиндексации полностью остановила все вызовы взаимоблокировок, которые мы видели ранее. Должен работать в качестве временного промежутка до тех пор, пока основная проблема не будет устранена и перенесена в выпуски EE / CE (в итоге мы купили расширение для этого).
источник
Я предлагаю вам установить Philwinkle DeadlockRetry. Это работает для нашей базы данных.
Я бы также посоветовал посмотреть на любые сторонние программы, попадающие в ваш веб-интерфейс. У нас был один, который обновлял QTY для продуктов, и это вызывало много тупиков. Мы переписали это и пошли прямо в базу данных.
источник
Я сталкивался с проблемой взаимоблокировки в прошлом году много раз, когда решал ее, просто увеличивая память для нашего сервера, потому что процесс индексации поглощает все ресурсы.
Вы также должны использовать решение async reindex, которое я использовал miravist
Для более стабильной системы вы должны подумать о том, чтобы отделить ваш бэкэнд от внешнего интерфейса, чтобы они не поглощали оперативную память друг друга.
По моему опыту, это не проблема исходного кода.
источник