Estou com um problema em que acredito que o processo de re-indexação do preço do produto está causando uma exceção de impasse no processo de checkout.
Eu peguei essa exceção no processo de checkout:
Exceção de conversão de ordem: SQLSTATE [40001]: Falha de serialização: 1213 Impasse encontrado ao tentar obter o bloqueio; tente reiniciar a transação
Infelizmente, não tenho um rastreamento de pilha completo por causa de onde a exceção foi capturada, mas, ao verificar o status INNODB, consegui rastrear o impasse:
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`
O bloqueio da tabela solicitante do SQL é finalmente gerado a partir de Mage_CatalogInventory_Model_Stock::registerProductsSale()
quando ele tenta obter a contagem atual de inventário para diminuí-la.
No momento em que ocorreu o conflito, o processo de re-indexação do Preço do Produto estava em execução e eu suponho que ele tivesse um bloqueio de leitura no catalog_product_entity table
que causou o conflito. Se eu estiver entendendo o impasse corretamente, qualquer bloqueio de leitura causará um impasse, mas o re-índice de preços do produto mantém o bloqueio por um tempo razoável, pois o site possui ~ 50.000 produtos.
Infelizmente, nesse ponto do fluxo do código de pagamento, o cartão de crédito do cliente havia sido cobrado (por meio de um módulo de pagamento personalizado) e a criação do objeto de pedido correspondente falhou.
Minhas perguntas são:
- A lógica do módulo de pagamento personalizado está com defeito? ou seja, existe um fluxo aceito para garantir que o Magento possa converter a cotação em uma exceção de pedido sem antes de confirmar a cobrança no método de pagamento (cartão de crédito)?
Edit: Parece que a lógica do módulo de pagamento está realmente com defeito, pois a chamada para $ paymentmethod-> authorize () deve ocorrer após o local em que esse impasse ocorre, não antes (conforme a resposta de Ivan abaixo). No entanto, a transação ainda será bloqueada pelo impasse (embora sem a cobrança incorreta no cartão de crédito).
Esta chamada de função
$stockInfo = $this->_getResource()->getProductsStock($this, array_keys($qtys), true);
emMage_CatalogInventory_Model_Stock::registerProductsSale()
torna uma leitura de bloqueio, o quão perigoso seria para torná-lo uma leitura sem bloqueio?Ao pesquisar na Web por uma resposta, alguns lugares sugeriram não executar uma nova indexação completa enquanto o site estiver quente; dificilmente parece uma boa solução; é a questão da indexação causando conflitos de tabela e contenção de bloqueios um problema conhecido no Magento, existem soluções alternativas?
Edit: Parece que a questão restante aqui é a da terceira questão; re-indexação causando deadlocks na tabela. Procurando soluções alternativas para isso.
Edit: O conceito de que os impasses não são, por si só, problemas, mas a resposta a eles deve ser o foco, faz muito sentido. Investigue mais para encontrar um ponto no código para capturar a exceção de conflito e reemitir a solicitação. Fazer isso no nível do adaptador Zend Framework DB é uma abordagem, mas também estou procurando uma maneira de fazer isso no código Magento para facilitar a manutenção.
Há um patch interessante neste segmento: http://www.magentocommerce.com/boards/viewthread/31666/P0/ que parece resolver uma condição de conflito relacionada (mas não esta especificamente).
Edit: Aparentemente, o impasse foi endereçado a um grau no CE 1.8 Alpha. Ainda estou procurando uma solução alternativa até que esta versão esteja fora do Alpha
Respostas:
Há uma probabilidade muito grande de que seu método de pagamento esteja processando o pagamento de forma incorreta.
O Processo de Salvamento de Pedidos Magento é bastante simples:
checkout_type_onepage_save_order
esales_model_service_quote_submit_before
Mage_CatalogInventory_Model_Stock::registerProductsSale()
é invocado neste observador de eventos$order->place()
método que processa o pagamento pelo telefone$paymentMethod->authorize()
,$paymentMethod->capture()
ou$paymentMethod->initialize()
depende de sua lógica.sales_flat_order_*
.Portanto, como você vê, não era possível, esse método de pagamento cobra dinheiro antes do bloqueio do inventário e lê os preços ou as informações do produto.
Só é possível se o método de pagamento for implementado de tal maneira, que ele execute o carregamento dos produtos com preços, após a execução da chamada de API para operação de cobrança.
Espero que isso ajude você a depurar seu problema.
Quanto à reindexação, deve ser seguro, se você não tiver esse problema com a forma de pagamento. Como a operação de leitura que depende dos bloqueios é realizada antes que o dinheiro seja cobrado.
fonte
registerProductsSale()
(entendendo que as correções no módulo de pagamento personalizado removerão o problema de cobrar o cartão do cliente).Como essa é uma extensão personalizada, podemos encontrar uma solução alternativa personalizada (leia-se: hack) para tentar novamente o salvamento sem editar os arquivos principais.
Eu resolvi todos os meus problemas de impasse com os dois métodos a seguir adicionados a uma classe auxiliar. Em vez de ligar,
$product->save()
chamo agoraMage::helper('mymodule')->saferSave($product)
:Isso realiza duas coisas distintas - enfileira uma nova tentativa quando um impasse é encontrado e define um tempo limite exponencialmente crescente para essa nova tentativa. Ele também define o nível de isolamento da transação. Há muitas informações sobre SO e DBA.SE para obter mais informações sobre os níveis de isolamento de transações do MySQL.
FWIW, não encontrei um impasse desde então.
fonte
$tries
para essa funçãosleep($this->getDelay());
Nos fóruns do Magento, eles falam sobre a edição de um arquivo de biblioteca do Zend: lib / Zend / Db / Statement / Pdo.php
A função _execute original:
Após modificação:
Como você pode ver, a única coisa que foi alterada é que as $ trips foram movidas para fora do loop.
Como sempre, é recomendável tentar isso em um ambiente de desenvolvimento / teste e não implantar instantaneamente essa correção em um ambiente de produção.
fonte
Eu tenho esse mesmo problema em um site Magento 1.11 e tenho um ticket aberto com o Magento desde 12/11/2012. Eles confirmaram que é um problema e devem estar criando um patch.
Minha pergunta é por que o preço precisa ser reindexado neste momento? Eu não acho que isso seja necessário:
fonte
Tivemos um problema de impasse semelhante quando certas chamadas foram feitas durante um re-índice. Para nós, isso se manifestava principalmente quando um cliente adicionava algo ao carrinho. Embora provavelmente não tenha resolvido o problema subjacente real, a implementação da re-indexação assíncrona interrompeu completamente todas as chamadas de conflito que estávamos vendo anteriormente. Deve funcionar como um intervalo até que o problema subjacente seja corrigido e enviado para as edições EE / CE (acabamos comprando uma extensão para isso).
fonte
Eu sugiro que você instale Philwinkle DeadlockRetry. Funcionou para o nosso banco de dados.
Eu também sugeriria que você observasse seus programas externos, atingindo sua API da Web. Tínhamos um que estava atualizando o QTY para produtos e estava causando muitos impasses. Reescrevemos isso e fomos diretamente para o banco de dados.
fonte
Eu encontrei um problema de impasse no ano passado muitas vezes, resolvi-o simplesmente aumentando a memória do nosso servidor, porque o processo de indexação consome todos os recursos.
Você também deve usar a solução de reindexação assíncrona que usei miravist
Para um sistema mais estável, você deve separar o back-end do front-end para que eles não consumam a RAM um do outro.
Para minha experiência, não é problema do código fonte.
fonte