Solicitações de página de administração de longa duração bloqueando outras solicitações

17

Se eu estiver conectado ao back-end do Magento e executar alguma tarefa que demore muito (pesquisa global em grandes catálogos, fluxo de dados demorado, etc.), meu navegador se recusará a carregar outras páginas de administrador apenas nesse navegador . Por que isso acontece e existe alguma ciência conhecida para soluções alternativas?

Ou seja, se eu

  1. Faça login na página do painel do Magento

  2. Abra uma segunda aba com qualquer página de administração do Magento

  3. Execute uma pesquisa global de longa duração (simulada com uma chamada para sleep(30)no início de globalSearchAction) na primeira guia

  4. Tentativa de recarregar a segunda guia

Comportamento esperado: a segunda guia carrega o conteúdo da página imediatamente

Comportamento real: a segunda guia é carregada apenas quando a pesquisa global de longa duração é concluída

Alguém sabe, especificamente, por que isso acontece? (Meu palpite é que as solicitações do console de administração do Magento bloqueiam alguns recursos que o Magento precisa para inicializar, mas não sei o que é isso)

Alguém sabe de uma correção / solução alternativa?

Alan Storm
fonte
1
Você, senhor, acabou de me enviar um desafio! :)
davidalger

Respostas:

21

O problema é causado por um bloqueio colocado pelo manipulador de sessões PHP. Portanto, não é o Magento que bloqueia explicitamente algo e tenta bloquear solicitações de administrador, mas quase um efeito colateral per-se do armazenamento de sessão baseado em arquivo.

Um bloqueio de gravação está sendo colocado no arquivo de dados da sessão quando ele é aberto pela inicial (de longa duração) pedido, fazendo com que o segundo pedido para o bloco até que o bloqueio é liberado quando ele chama session_startemMage_Core_Model_Session_Abstract_Varien::start

Isso é 100% reproduzível. Eu usei o mesmo método que você, adicionando um sleep(30)ao topoMage_Adminhtml_IndexController::globalSearchAction

Vale notar que isso não pode ser reproduzido se você estiver usando o armazenamento de sessão do db. Depois de encontrar a causa raiz, configurei uma sandbox para armazenamento de sessão no banco de dados e não consegui mais reproduzir o problema. Portanto, os manipuladores de sessão no banco de dados Magento aparentemente não usam o bloqueio no nível da linha para bloquear gravações de sessão. Acho isso interessante, porque tem o potencial de perda de dados da sessão, pois o aplicativo obviamente não está respondendo por vários threads gravados na mesma sessão. Nota para os leitores: eu nunca usaria o armazenamento de sessões db na produção para tentar resolver isso, isso é bom apenas para sobrecarregar o banco de dados MySql.

Não tentei reproduzir o comportamento usando sistemas de armazenamento de sessões baseados em memória, como Redis, mas meu palpite é que o bloqueio dos registros no repositório de sessões provavelmente também foi ignorado.

Existem técnicas que podem ser empregadas para evitar isso, como usar session_write_closepara liberar o bloqueio antes de iniciar um trabalho de longa duração. Mas isso também impediria que você escrevesse para a sessão, uma vez que você a fechou. Portanto, não é provável que seja prontamente implementado no Magento, mas pode ser implementado em rotas / controladores específicos.

Minha técnica para fixar isso como causa principal foi habilitar o criador de perfil Xdebug e examinar o arquivo "cachegrind". Depois que a segunda solicitação foi concluída, carreguei o arquivo de saída (~ 25 MB de log) no MacCallGrind e procurei o rastreamento seguindo o caminho das chamadas em que o tempo inclusivo era de 28 segundos ou mais. Isso me levou à session_startligação que levou cerca de 28 segundos para ser executada, o que me deu um ótimo ponto para pesquisar.

EDIT: Para os interessados, publiquei uma captura de tela do arquivo "cachegrind" exibido no MacCallGrind no Twitter.

davidalger
fonte
O módulo uRapidFlow da Unirgy fecha a sessão para evitar esse problema, o que é bom de certa forma, mas é frustrante por dificultar o fornecimento de feedback ao usuário posteriormente.
Peter O'Callaghan
@davidalger - Com qual armazenamento de sessão você costuma implantar para sites clientes?
Alan Storm
3
Re: bloquear o arquivo da sessão PHP, isso é menos para a integridade dos dados do que para a integridade do próprio arquivo no disco. Ter vários processos abrindo e gravando em bits no disco (que é o que é um arquivo) levará rapidamente à corrupção dos dados. MySQL, redis e a maioria dos bancos de dados são projetados especificamente para permanecer consistentes, mesmo que haja várias gravações quase ao mesmo tempo. ou seja, não é que o bloqueio foi esquecido, é que não é tão necessário.
Alan Storm
@AlanStorm - Uma instância dedicada do Memcached para uma instalação com balanceamento de carga, sistema de arquivos para clusters de nó de aplicativo único. O sistema de arquivos tem um desempenho melhor quando você não possui vários nós, pois não possui latência de IP.
Davidalger 15/05
Correto, bloquear o arquivo tem tudo a ver com impedir a corrupção de dados. No entanto, manter o bloqueio até que a sessão seja fechada é sobre como evitar a perda de dados. Se dois processos carregarem os dados da sessão, modificá-los e depois gravá-los, um deles terá suas modificações substituídas. Geralmente, isso não representa um problema crítico, mas pode causar perda de dados e / ou problemas difíceis de depurar.
Davidalger 15/05