Heroku Postgres - termina a consulta suspensa (ocioso na transação)

99

Estou usando o Heroku com a opção Crane Postgres e estava executando uma consulta no banco de dados de minha máquina local quando minha máquina local travou. Se eu correr

select * from pg_stat_activity

uma das entradas tem

<IDLE> in transaction

na coluna current_query_text.

Como resultado, não posso descartar a tabela que estava sendo gravada pela consulta que foi encerrada. Tentei usar pg_cancel_backend (N) e ele retorna True, mas nada parece acontecer.

Como posso encerrar este processo para poder largar a mesa?

alan
fonte
1
Talvez a pergunta deva ser reformulada para "como faço para encerrar minha própria consulta quando não tenho acesso root ao servidor postgres nem acesso de superusuário ao banco de dados". Parece uma pergunta muito boa mesmo ... e não sei a resposta.
tobixen

Respostas:

138

Esta é uma resposta geral do Postgres, e não específica para heroku


(A resposta simples e estúpida para esta pergunta pode ser ... apenas reinicie o postgresql. Supondo que isso não seja desejável ou não seja uma opção ...)

Encontre o PID executando este sql:

SELECT pid , query, * from pg_stat_activity
  WHERE state != 'idle' ORDER BY xact_start;

(A consulta pode precisar de conserto dependendo da versão do postgres - eventualmente, basta selecionar * em pg_stat_activity). Você encontrará o pid na primeira coluna (à esquerda) e a primeira linha (superior) provavelmente será a consulta que você gostaria de encerrar. Vou assumir que o pid é 1234 abaixo.

Você pode cancelar uma consulta por meio de SQL (ou seja, sem acesso shell), desde que seja sua ou tenha acesso de superusuário:

select pg_cancel_backend(1234);

Essa é uma solicitação "amigável" para cancelar a consulta 1234 e, com alguma sorte, ela desaparecerá depois de um tempo. Eventualmente, isso é mais eficiente:

select pg_terminate_backend(1234);

Se você tiver acesso ao shell e permissões de root ou postgres, também poderá fazer isso no shell. Para "cancelar", pode-se fazer:

kill -INT 1234

e para "encerrar", simplesmente:

kill 1234

NÃO:

kill -9 1234

... isso freqüentemente resultará em todo o servidor postgres caindo em chamas, então você pode reiniciar o postgres. Postgres é bastante robusto, então os dados não serão corrompidos, mas eu recomendo não usar "kill -9" em qualquer caso :-)


Uma "transação ociosa" de longa duração geralmente significa que a transação não foi encerrada com um "commit" ou um "rollback", o que significa que o aplicativo está cheio de bugs ou não foi projetado corretamente para funcionar com bancos de dados transacionais. Deve-se evitar "ociosidade na transação" de longa duração, pois isso também pode causar grandes problemas de desempenho.

Tobixen
fonte
Tentei pg_cancel_backend sem sucesso. Não tenho acesso ao shell e não sou superusuário, então não posso enviar um SIGKILL usando pg_terminate_backend
alan
Qual versão do postgres você está usando? (dica:) select version(). Você recebe alguma mensagem de erro ao usar pg_cancel_backend?
tobixen 02 de
Fiz uma tentativa de usar o pg_cancel_backend por conta própria, então recebi a mensagem de erro "deve ser superusuário para sinalizar outros processos do servidor" ... significando que aparentemente você precisará de acesso root no servidor ou acesso db através de algum superusuário postgres (ou seja, usuário postgres ) para eliminar sua própria consulta. Isso parece um pouco péssimo :-(
tobixen
1
acontece que os processos foram cancelados por pg_cancel_backend, mas as consultas ainda aparecem em pg_stat_activity por um tempo
alan
Talvez seja específico do Heroku. Pelo que posso ver, no postgres comum é realmente necessário ser superusuário para eliminar um processo travado (estou testando com "select pg_sleep (3600);" na página 8.4, e recebo "ERRO: deve ser superusuário para sinalizar outros processos do servidor "). Porém, novamente "ocioso na transação" não é exatamente o mesmo.
tobixen
36

Experimente isto:

select pg_terminate_backend(pid int)

Mais sobre isso você pode encontrar aqui . Esta deve ser uma solução 'mais limpa' para este problema do que eliminar processo por sistema.

evgenek
fonte
Adicione como obter o seu pid para a sua resposta
alpinista
19

Você pode instalar o heroku-pg-extrasadd-on e executar o seguinte comando para obter o PID:

heroku pg:locks --app <your-app>

Depois é só fazer:

heroku pg:kill <pid> --app <your-app> 

NOTA : a --forceopção pode ser usada para emitir pg_terminate_backend que interrompe a conexão inteira para essa consulta.

Se heroku pg:locksnão listar nada, tente heroku pg:ps.

Para mais informações, acesse:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco
fonte
Obrigado. Ainda não consigo encerrar a transação / PID ... meu computador travou durante uma importação e não consigo encerrar o PID. :(
dimitarvp
-3

Podemos usar o seguinte para alcançá-lo em uma única consulta:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codificadores da escuridão
fonte
isso eliminaria todas as consultas em execução, então é melhor reiniciar o postgres. ordenar por xact_start e limitar 1, e eu poderia concordar ... mas, novamente, eu preferiria olhar a lista antes de matar às cegas.
Tobixen
que tal isso? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN