Heroku Postgres - terminer la requête bloquée (inactif dans la transaction)

99

J'utilise Heroku avec l'option Crane Postgres et j'exécutais une requête sur la base de données à partir de ma machine locale lorsque ma machine locale s'est plantée. Si je cours

select * from pg_stat_activity

l'une des entrées a

<IDLE> in transaction

dans la colonne current_query_text.

Par conséquent, je ne peux pas supprimer la table sur laquelle était écrite la requête terminée. J'ai essayé d'utiliser pg_cancel_backend (N) et il renvoie True mais rien ne semble se produire.

Comment puis-je mettre fin à ce processus afin de pouvoir supprimer la table?

Alan
la source
1
Peut-être que la question devrait être reformulée en «comment terminer ma propre requête sans avoir ni accès root au serveur postgres ni accès superutilisateur à la base de données». Cela semble être une très bonne question en effet ... et je ne connais pas la réponse.
tobixen

Réponses:

138

Ceci est une réponse Postgres générale, et non spécifique à heroku


(La réponse simple-stupide à cette question peut être ... il suffit de redémarrer postgresql. En supposant que ce n'est pas souhaitable ou pas une option ...)

Trouvez le PID en exécutant ce sql:

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

(La requête peut avoir besoin d'être réparée en fonction de la version de postgres - éventuellement, sélectionnez simplement * dans pg_stat_activity). Vous trouverez le pid dans la première colonne (à gauche) et la première ligne (en haut) est probablement la requête que vous souhaitez terminer. Je suppose que le pid est 1234 ci-dessous.

Vous pouvez annuler une requête via SQL (c'est-à-dire sans accès shell) tant qu'elle vous appartient ou que vous disposez d'un accès super utilisateur:

select pg_cancel_backend(1234);

C'est une demande "amicale" pour annuler la requête 1234, et avec un peu de chance, elle disparaîtra après un certain temps. Finalement, c'est plus efficace:

select pg_terminate_backend(1234);

Si vous avez un accès au shell et des autorisations root ou postgres, vous pouvez également le faire depuis le shell. Pour "annuler" on peut faire:

kill -INT 1234

et pour "terminer", il suffit:

kill 1234

NE PAS:

kill -9 1234

... Cela entraînera souvent un incendie dans tout le serveur postgres, alors vous pouvez aussi redémarrer postgres. Postgres est assez robuste, donc les données ne seront pas corrompues, mais je recommande de ne pas utiliser "kill -9" dans tous les cas :-)


Un «inactif dans la transaction» de longue durée signifie souvent que la transaction n'a pas été terminée par un «commit» ou un «rollback», ce qui signifie que l'application est boguée ou n'est pas correctement conçue pour fonctionner avec des bases de données transactionnelles. Une «inactivité dans la transaction» de longue durée doit être évitée, car elle peut également entraîner des problèmes de performances majeurs.

Tobixen
la source
J'ai essayé pg_cancel_backend en vain. Je n'ai pas d'accès au shell et je ne suis pas un super-utilisateur, donc je ne peux pas envoyer un SIGKILL en utilisant pg_terminate_backend
alan
Quelle version de postgres utilisez-vous? (indice:) select version(). Recevez-vous des messages d'erreur lors de l'utilisation pg_cancel_backend?
tobixen
J'ai essayé d'utiliser pg_cancel_backend moi-même, donc j'ai reçu le message d'erreur "doit être superutilisateur pour signaler les autres processus du serveur" ... ce qui signifie qu'apparemment, vous aurez besoin d'un accès root sur le serveur ou d'un accès db via un super utilisateur postgres (c'est-à-dire l'utilisateur postgres ) pour tuer votre propre requête. Cela semble un peu
nul
1
il s'avère que les processus ont été annulés par pg_cancel_backend mais les requêtes s'affichent toujours dans pg_stat_activity pendant un certain temps
alan
C'est peut-être spécifique à Heroku. Autant que je puisse voir, sous des postgres ordinaires, il est vraiment nécessaire d'être superutilisateur pour tuer un processus bloqué (je teste avec "select pg_sleep (3600);" sur pg 8.4, et j'obtiens "ERREUR: doit être superutilisateur pour signaler autres processus serveur "). Cependant, là encore, «inactif dans la transaction» n'est pas tout à fait la même chose.
tobixen
36

Essaye ça:

select pg_terminate_backend(pid int)

Pour en savoir plus, cliquez ici . Cela devrait être une solution «plus propre» de ce problème que de tuer processus par système.

Evgenek
la source
Veuillez ajouter comment obtenir votre pid à votre réponse
mountainclimber
19

Vous pouvez installer le heroku-pg-extrasmodule complémentaire et exécuter la commande suivante pour obtenir le PID:

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

Alors faites simplement:

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

REMARQUE : l' --forceoption peut être utilisée pour émettre pg_terminate_backend qui supprime toute la connexion pour cette requête.

Si heroku pg:locksne répertorie rien, essayez heroku pg:ps.

Pour plus d'informations, consultez:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco
la source
Je vous remercie. Cependant, je ne peux toujours pas terminer la transaction / le PID ... mon ordinateur a gelé le matériel lors d'une importation et je ne parviens pas à terminer le PID. :(
dimitarvp
-3

Nous pouvons utiliser ce qui suit pour y parvenir en une seule requête:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codeurs du noir
la source
cela tuerait toutes les requêtes en cours, alors on peut aussi redémarrer postgres. order by xact_start et limit 1, et je pourrais être d'accord ... mais là encore, je préférerais regarder la liste avant de tuer aveuglément.
tobixen le
Et ça? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN