Występuje problem, który moim zdaniem powoduje, że proces ponownego indeksowania ceny produktu powoduje wyjątek impasu w procesie realizacji transakcji.
Złapałem ten wyjątek podczas realizacji transakcji:
Wyjątek konwersji zamówienia: SQLSTATE [40001]: Błąd serializacji: 1213 Podczas próby uzyskania blokady znaleziono zakleszczenie; spróbuj ponownie uruchomić transakcję
Niestety nie mam śledzenia pełnego stosu z powodu miejsca, w którym został przechwycony wyjątek, ale sprawdzając status INNODB udało mi się wyśledzić impas:
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`
Blokowanie tabeli SQL żądającej jest ostatecznie generowane, Mage_CatalogInventory_Model_Stock::registerProductsSale()
gdy próbuje uzyskać bieżącą liczbę zapasów w celu jej zmniejszenia.
W momencie wystąpienia zakleszczenia proces ponownego indeksowania ceny produktu był uruchomiony i zakładam, że miał blokadę odczytu, catalog_product_entity table
która spowodowała zakleszczenie. Jeśli dobrze rozumiem zakleszczenie, każda blokada odczytu spowoduje zakleszczenie, ale ponowne indeksowanie ceny produktu utrzymuje blokadę przez długi czas, ponieważ witryna zawiera ~ 50 000 produktów.
Niestety, w tym momencie w kodzie przepływu transakcji karta kredytowa klienta została obciążona (za pomocą niestandardowego modułu płatności), a utworzenie odpowiedniego obiektu zamówienia nie powiodło się.
Moje pytania to:
- Czy logika niestandardowego modułu płatności jest wadliwa? tj. Czy istnieje akceptowany przepływ zapewniający, że Magento może bezpłatnie przekonwertować ofertę na wyjątek zamówienia przed obciążeniem metodą płatności (kartą kredytową)?
Edycja: Wygląda na to, że logika modułu płatniczego jest rzeczywiście błędna, ponieważ wywołanie $ paymentmethod-> autoryzacja () powinno nastąpić po miejscu, w którym występuje ten impas, a nie wcześniej (zgodnie z odpowiedzią Iwana poniżej). Jednak transakcja będzie nadal blokowana przez impas (choć bez błędnego obciążenia karty kredytowej).
To wywołanie funkcji
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
wMage_CatalogInventory_Model_Stock::registerProductsSale()
sprawia, że odczyt zamek, jak niebezpieczne byłoby zrobić to bez blokowania odczytu?Szukając odpowiedzi w Internecie, kilka miejsc zasugerowało, aby nie przeprowadzać pełnego ponownego indeksowania, gdy witryna jest gorąca; nie wydaje się dobrym rozwiązaniem; czy problem indeksowania powodujący zakleszczenia tabeli i rywalizację o blokady jest znanym problemem w Magento, czy istnieją obejścia?
Edycja: Wydaje się, że pozostałe pytanie tutaj to pytanie trzecie; ponowne indeksowanie powodujące zakleszczenia tabeli. Szukasz obejścia tego problemu.
Edycja: Koncepcja, że impasy nie są same w sobie problemami, a raczej reakcja na nie powinna być przedmiotem zainteresowania, ma wiele sensu. Dalsze dochodzenie w celu znalezienia punktu w kodzie w celu uchwycenia wyjątku zakleszczenia i ponownego wysłania żądania. Robienie tego na poziomie adaptera DB Zend Framework to jedno podejście, ale szukam również sposobu na wykonanie tego w kodzie Magento w celu ułatwienia konserwacji.
W tym wątku znajduje się interesująca łatka: http://www.magentocommerce.com/boards/viewthread/31666/P0/, która wydaje się rozwiązywać powiązany warunek impasu (ale nie ten konkretnie).
Edycja: Najwyraźniej impas został rozwiązany do pewnego stopnia w CE 1.8 Alpha. Wciąż szukam obejścia, dopóki ta wersja nie będzie w wersji alfa
Odpowiedzi:
Istnieje duże prawdopodobieństwo, że Twoja metoda płatności nieprawidłowo przetwarza płatność.
Proces zapisywania zamówień Magento jest dość prosty:
checkout_type_onepage_save_order
isales_model_service_quote_submit_before
Mage_CatalogInventory_Model_Stock::registerProductsSale()
jest wywoływany w tym obserwatorze zdarzeń$order->place()
metody, która przetwarza płatności dzwoni$paymentMethod->authorize()
,$paymentMethod->capture()
lub$paymentMethod->initialize()
zależy od jego logiki.sales_flat_order_*
.Jak widać, nie było możliwe, aby ta metoda płatności pobierała pieniądze przed zablokowaniem zapasów i odczytaniem cen produktów lub informacji o produkcie.
Jest to możliwe tylko w przypadku, gdy metoda płatności jest zaimplementowana w taki sposób, że sama ładuje produkty z cenami, po wykonaniu wezwania API do operacji ładowania.
Mam nadzieję, że pomoże to w debugowaniu problemu.
Jeśli chodzi o reindeksowanie, powinno być bezpieczne, jeśli nie masz tego problemu z metodą płatności. Ponieważ operacja odczytu zależna od blokad jest wykonywana przed naliczeniem pieniędzy.
źródło
registerProductsSale()
(zrozumienie, że dzięki poprawkom niestandardowego modułu płatności usunie problem z obciążeniem karty klienta).Ponieważ jest to niestandardowe rozszerzenie, możemy znaleźć niestandardowe obejście (czytaj: włamać się) do ponownej próby zapisania bez edycji podstawowych plików.
Rozwiązałem wszystkie moje problemy z impasem, dodając dwie następujące metody do klasy pomocników. Zamiast dzwonić
$product->save()
, teraz dzwonięMage::helper('mymodule')->saferSave($product)
:Osiąga to dwie różne rzeczy - ustawia kolejkę ponawiania próby napotkania impasu i ustawia wykładniczo zwiększający się limit czasu dla tej ponownej próby. Ustawia także poziom izolacji transakcji. Istnieje wiele informacji na temat SO i DBA.SE, aby uzyskać więcej informacji na temat poziomów izolacji transakcji MySQL.
FWIW, od tego czasu nie spotkałem impasu.
źródło
$tries
do tej funkcjisleep($this->getDelay());
Na forach Magento rozmawiają o edycji pliku biblioteki Zend: lib / Zend / Db / Statement / Pdo.php
Oryginalna funkcja _execute:
Po modyfikacji:
Jak widać, jedyną rzeczą, która została zmieniona, jest to, że $ try został przeniesiony poza pętlę.
Jak zawsze zaleca się wypróbowanie tego w środowisku programistycznym / testowym i niezwłoczne wdrożenie tej poprawki w środowisku produkcyjnym.
źródło
Mam ten sam problem na stronie Magento 1.11 i mam otwarty bilet z Magento na nim od 11.12.2012. Potwierdzili, że jest to problem i prawdopodobnie tworzą łatkę.
Moje pytanie brzmi: dlaczego w tym momencie cena musi być ponownie zindeksowana? Nie sądzę, że jest to potrzebne:
źródło
Mieliśmy podobny problem z impasem, gdy podczas ponownego indeksowania wykonano pewne połączenia. Przejawiało się to przede wszystkim wtedy, gdy klient dodawał coś do koszyka. Prawdopodobnie nie naprawiając rzeczywistego problemu, wdrożenie asynchronicznego ponownego indeksowania całkowicie zatrzymało wszystkie wywołane przez nas zakleszczenia. Powinien działać jako przerwa, dopóki problem nie zostanie naprawiony i nie zostanie przekazany do edycji EE / CE (w końcu kupiliśmy rozszerzenie, aby to zrobić).
źródło
Sugeruję zainstalowanie Philwinkle DeadlockRetry. Działa z naszą bazą danych.
Sugerowałbym również, aby spojrzeć na twoje programy zewnętrzne uderzające w twój interfejs API. Mieliśmy taki, który aktualizował QTY produktów i powodował wiele impasów. Napisaliśmy to na nowo i przeszliśmy bezpośrednio do bazy danych.
źródło
W zeszłym roku spotkałem się z problemem impasu wiele razy go rozwiązałem, po prostu zwiększając pamięć dla naszego serwera, ponieważ proces indeksowania pochłania wszystkie zasoby.
Powinieneś także nam asynchronizować rozwiązanie reindex, którego użyłem miravist
Aby uzyskać bardziej stabilny system, powinieneś pomyśleć o oddzieleniu backendu od frontendu, aby nie zjadali sobie pamięci RAM.
Z mojego doświadczenia wynika, że nie jest to problem z kodem źródłowym.
źródło