Estoy experimentando un problema en el que creo que el proceso de reindexación del precio del producto está causando una excepción de punto muerto en el proceso de pago.
Capté esta excepción en el proceso de pago:
Excepción de conversión de orden: SQLSTATE [40001]: error de serialización: 1213 Punto muerto encontrado al intentar bloquear; intente reiniciar la transacción
Desafortunadamente, no tengo un seguimiento completo de la pila debido a dónde se detectó la excepción, pero al verificar el estado de INNODB pude rastrear el punto muerto:
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`
El bloqueo de la tabla de solicitud de SQL se genera en última instancia Mage_CatalogInventory_Model_Stock::registerProductsSale()
cuando se intenta obtener el recuento de inventario actual para disminuirlo.
En el momento en que se produjo el punto muerto, el proceso de reindexación del precio del producto se estaba ejecutando y supongo que tenía un bloqueo de lectura catalog_product_entity table
que causó el punto muerto. Si entiendo el punto muerto correctamente, cualquier bloqueo de lectura provocará un punto muerto, pero el re-índice del precio del producto mantiene el bloqueo durante un tiempo justo ya que el sitio tiene ~ 50,000 productos.
Desafortunadamente, en este punto del flujo del código de pago, la tarjeta de crédito del cliente había sido cargada (a través de un módulo de pago personalizado) y la creación del objeto de pedido correspondiente falló.
Mis preguntas son:
- ¿La lógica del módulo de pago personalizado es defectuosa? es decir, ¿hay un flujo aceptado para garantizar que Magento pueda convertir la cotización a una orden de excepción gratis antes de comprometer el cargo al método de pago (tarjeta de crédito)?
Editar: Parece que la lógica del módulo de pago es realmente defectuosa ya que la llamada a $ paymentmethod-> authorize () debería ocurrir después del lugar donde se produce este punto muerto, no antes (según la respuesta de Ivan a continuación). Sin embargo, la transacción seguirá siendo bloqueada por el punto muerto (aunque sin el cargo erróneo a la tarjeta de crédito).
Esta llamada a la función
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
enMage_CatalogInventory_Model_Stock::registerProductsSale()
la convierte en una lectura de bloqueo, lo peligroso que sería para que sea una lectura sin bloqueo?Al buscar en la web una respuesta, un par de lugares sugirieron no ejecutar una reindexación completa mientras el sitio está activo; difícilmente parece una buena solución; ¿Es el problema de la indexación que causa puntos muertos de tabla y contención de bloqueo un problema conocido en Magento? ¿Hay soluciones alternativas?
Editar: Parece que la pregunta restante aquí es la de la tercera pregunta; reindexar causando puntos muertos en la tabla. Buscando soluciones para esto.
Editar: el concepto de que los puntos muertos no están en sí mismos, sino que la respuesta a ellos debería ser el foco, tiene mucho sentido. Investigando más a fondo para encontrar un punto en el código para detectar la excepción de punto muerto y volver a emitir la solicitud. Hacer esto en el nivel del adaptador Zend Framework DB es un enfoque, pero también estoy buscando una manera de hacerlo en el código de Magento para facilitar el mantenimiento.
Hay un parche interesante en este hilo: http://www.magentocommerce.com/boards/viewthread/31666/P0/ que parece resolver una condición de punto muerto relacionada (pero no esta específicamente).
Editar: Aparentemente, el punto muerto se ha abordado hasta cierto punto en CE 1.8 Alpha. Todavía estoy buscando una solución hasta que esta versión esté fuera de Alpha
Respuestas:
Existe una gran probabilidad de que su método de pago esté procesando el pago incorrectamente.
El proceso de guardado de pedidos de Magento es bastante simple:
checkout_type_onepage_save_order
ysales_model_service_quote_submit_before
Mage_CatalogInventory_Model_Stock::registerProductsSale()
se invoca en este evento observador$order->place()
método que procesa el pago llamando$paymentMethod->authorize()
,$paymentMethod->capture()
o$paymentMethod->initialize()
depende de su lógica.sales_flat_order_*
.Como puede ver, no podría ser posible, ese método de pago cobra dinero antes del bloqueo del inventario y la lectura de los precios del producto o la información del producto.
Solo es posible en caso de que el método de pago se implemente de tal manera que realice la carga de los productos con los precios, después de que se realice la llamada API para la operación de cobro.
Espero que esto te ayude a depurar tu problema.
En cuanto a la reindexación, debería ser seguro, si no tiene este problema con el método de pago. Dado que la operación de lectura que depende de las cerraduras se realiza antes de que se cobre el dinero.
fuente
registerProductsSale()
(comprender que con las correcciones al módulo de pago personalizado se eliminará el problema de que se cargue la tarjeta del cliente).Debido a que esta es una extensión personalizada, podemos encontrar una solución personalizada (leer: piratear) para volver a intentar guardar sin editar archivos principales.
He resuelto todos mis problemas de punto muerto con los siguientes dos métodos agregados a una clase auxiliar. En lugar de llamar
$product->save()
, ahora llamoMage::helper('mymodule')->saferSave($product)
:Esto logra dos cosas distintas: pone en cola un reintento cuando se encuentra un punto muerto y establece un tiempo de espera exponencialmente creciente para ese reintento. También establece el nivel de aislamiento de la transacción. Hay mucha información sobre SO y DBA.SE para obtener más información sobre los niveles de aislamiento de transacciones de MySQL.
FWIW, no he encontrado un punto muerto desde entonces.
fuente
$tries
a esta funciónsleep($this->getDelay());
En los foros de Magento hablan sobre la edición de un archivo de biblioteca Zend: lib / Zend / Db / Statement / Pdo.php
La función original _execute:
Después de la modificación:
Como puede ver, lo único que se ha cambiado es que los $ tries se han movido fuera del ciclo.
Como siempre, se sugiere probar esto en un entorno de desarrollo / prueba y no implementar instantáneamente esta solución en un entorno de producción.
fuente
Tengo este mismo problema en un sitio de Magento 1.11 y tengo un ticket abierto con Magento desde el 12/11/2012. Confirmaron que es un problema y se supone que crean un parche.
Mi pregunta es ¿por qué el precio debe reindexarse en este momento? No creo que esto sea necesario:
fuente
Tuvimos un problema de punto muerto similar cuando se realizaron ciertas llamadas durante una reindexación. Para nosotros, se manifestó principalmente cuando un cliente agregaría algo al carrito. Aunque probablemente no solucione el problema subyacente real, la implementación de la reindexación asincrónica ha detenido por completo todas las llamadas de punto muerto que estábamos viendo anteriormente. Debería funcionar como un espacio intermedio hasta que se solucione el problema subyacente y se envíe a las ediciones EE / CE (terminamos comprando una extensión para hacerlo).
fuente
Le sugiero que instale Philwinkle DeadlockRetry. Funcionó para nuestra base de datos.
También sugeriría mirar cualquier programa externo que golpee su API web. Tuvimos uno que estaba actualizando la CANTIDAD para los productos y estaba causando muchos puntos muertos. Reescribimos eso y fuimos directamente a la base de datos.
fuente
Encontré un problema de punto muerto el año pasado muchas veces lo resolví simplemente aumentando la memoria para nuestro servidor porque el proceso de indexación consume todos los recursos.
También debe usar la solución de reindexación asíncrona que utilicé miravist
Para un sistema más estable, debe pensar en separar su backend de la interfaz para que no se coman la RAM del otro.
Para mi experiencia, no es un problema de código fuente.
fuente