Heroku Postgres: termina la consulta colgada (inactiva en la transacción)

99

Estoy usando Heroku con la opción Crane Postgres y estaba ejecutando una consulta en la base de datos desde mi máquina local cuando mi máquina local falló. Si corro

select * from pg_stat_activity

una de las entradas tiene

<IDLE> in transaction

en la columna current_query_text.

Como resultado, no puedo eliminar la tabla en la que estaba escribiendo la consulta que terminó. Intenté usar pg_cancel_backend (N) y devuelve True, pero parece que no sucede nada.

¿Cómo puedo finalizar este proceso para poder dejar la mesa?

Alan
fuente
1
Quizás la pregunta debería reformularse como "cómo termino mi propia consulta cuando no tengo acceso de root al servidor de Postgres ni acceso de superusuario a la base de datos". Realmente parece una muy buena pregunta ... y no sé la respuesta.
tobixen

Respuestas:

138

Esta es una respuesta general de Postgres, y no específica de heroku


(La respuesta simple y estúpida a esta pregunta puede ser ... simplemente reinicie postgresql. Suponiendo que eso no sea deseable o no sea una opción ...)

Encuentre el PID ejecutando este sql:

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

(Es posible que sea necesario corregir la consulta dependiendo de la versión de postgres; eventualmente, solo seleccione * de pg_stat_activity). Encontrará el pid en la primera columna (izquierda), y es probable que la primera fila (superior) sea la consulta que le gustaría terminar. Asumiré que el pid es 1234 a continuación.

Puede cancelar una consulta a través de SQL (es decir, sin acceso de shell) siempre que sea suya o tenga acceso de superusuario:

select pg_cancel_backend(1234);

Esa es una solicitud "amigable" para cancelar la consulta 1234 y, con algo de suerte, desaparecerá después de un tiempo. Eventualmente, esto es más eficiente:

select pg_terminate_backend(1234);

Si tiene acceso al shell y permisos de root o postgres, también puede hacerlo desde el shell. Para "cancelar" uno puede hacer:

kill -INT 1234

y para "terminar", simplemente:

kill 1234

NO HAGA:

kill -9 1234

... que a menudo resultará en que todo el servidor de postgres se incendie, entonces también puede reiniciar postgres. Postgres es bastante robusto, por lo que los datos no se dañarán, pero recomendaría no usar "kill -9" en cualquier caso :-)


Un "inactivo en la transacción" de larga duración a menudo significa que la transacción no se terminó con un "compromiso" o un "retroceso", lo que significa que la aplicación tiene errores o no está correctamente diseñada para funcionar con bases de datos transaccionales. Debe evitarse el "inactivo en la transacción" de larga duración, ya que también puede causar importantes problemas de rendimiento.

tobixen
fuente
Intenté pg_cancel_backend sin éxito. No tengo acceso a una consola y no soy un superusuario así que no puedo enviar un SIGKILL usando pg_terminate_backend
Alan
¿Qué versión de postgres estás usando? (pista:) select version(). ¿Recibe algún mensaje de error al usarlo pg_cancel_backend?
tobixen
Intenté usar pg_cancel_backend yo mismo, por lo que recibí el mensaje de error "debe ser superusuario para señalar otros procesos del servidor" ... lo que significa que aparentemente necesitará acceso de root en el servidor o acceso a la base de datos a través de algún superusuario de postgres (es decir, usuario de postgres ) para eliminar su propia consulta. Eso parece
apestar
1
resulta que los procesos fueron cancelados por pg_cancel_backend pero las consultas todavía se muestran en pg_stat_activity por un tiempo
Alan
Quizás sea específico de Heroku. Por lo que puedo ver, en postgres ordinarios realmente se necesita ser superusuario para eliminar un proceso atascado (estoy probando con "select pg_sleep (3600);" en la página 8.4, y obtengo "ERROR: debe ser superusuario para señalar otros procesos del servidor "). Aunque, de nuevo, "inactivo en la transacción" no es exactamente lo mismo.
tobixen
36

Prueba esto:

select pg_terminate_backend(pid int)

Puedes encontrar más sobre esto aquí . Esta debería ser una solución 'más limpia' de este problema que matar proceso por sistema.

evgenek
fuente
Agregue cómo obtener su pid a su respuesta
mountainclimber
19

Puede instalar el heroku-pg-extrascomplemento y ejecutar el siguiente comando para obtener el PID:

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

Entonces solo haz:

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

NOTA : la --forceopción se puede usar para emitir pg_terminate_backend que descarta toda la conexión para esa consulta.

Si heroku pg:locksno incluye nada, inténtelo heroku pg:ps.

Para obtener más información, consulte:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco
fuente
Gracias. Sin embargo, todavía no puedo terminar la transacción / PID ... mi computadora se ha congelado durante una importación y no puedo terminar el PID. :(
dimitarvp
-3

Podemos utilizar lo siguiente para lograrlo en una sola consulta:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codificadores de la oscuridad
fuente
eso mataría todas las consultas en ejecución, entonces también se puede reiniciar postgres. order by xact_start y limit 1, y podría estar de acuerdo ... pero, de nuevo, preferiría mirar la lista antes de matar a ciegas.
tobixen
que hay de esto SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN