Чи перервано давній запит Postgres, якщо зв’язок втрачено / порушено?


21

Якщо я відкрию підключення до Postgres і видаю тривалий запит, а потім розірваю з'єднання (наприклад, вбиваю клієнтський процес, який відкрив з'єднання), чи триватиме тривалий запит і далі він буде автоматично перерваний? Це налаштовується?

(Я використовую Postgresql 9.2.9)

Відповіді:


32

"Це залежить".

Якщо клієнт зникає через втрату з’єднання з мережею, запит, як правило, запускається, поки не буде отримано достатньо рядків, щоб заповнити його мережевий буфер відправки, а потім зупинитися і застрягнути до тих пір, поки TCP-з'єднання не впаде, і в цей момент він перерветься. Якщо він завершиться до заповнення буфера відправлення TCP, він буде успішно виконаний, тому, якщо він автоматично заповнить, запит буде здійснено.

Якщо клієнт убитий таким чином, що операційна система клієнта може звітувати перед сервером через TCP RST (наприклад, segfault / аварія клієнта, SIGTERM, SIGKILL тощо), сервер PostgreSQL встановить прапор переривання. Наступного разу, коли запит перевірятиме наявність перерв під час його виконання, він побачить прапор і перерве. Іноді запит може робити важку для процесора роботу в коді, який не перевіряє на наявність переривань - деякі розширення та кілька місць в ядрі PostgreSQL - в цьому випадку він може не помічати переривання протягом тривалого часу і продовжувати працювати. Це майже завжди буде бачити переривання і переривати, перш ніж завершити і зробити, якщо це автоматично підключення.

Якщо клієнт вбивається чимось на кшталт раптової перезавантаження ОС, так що клієнт- хост раптом нічого не знає про TCP-з'єднання, але все ще може відповісти в мережі, запит, ймовірно, буде перервано в перший раз, коли він намагається написати рядок, наприклад Джефф сказав, тому що хост клієнта відправить TCP RST у відповідь на перший пакет, надісланий сервером після перезавантаження. PostgreSQL перевіряє наявність перерв у кожному рядку, який він надсилає.

Таку поведінку не можна налаштувати. Що стосується PostgreSQL, якщо клієнт піде, його завдання полягає у припиненні будь-яких запитів, які виконував клієнт. Щоб змінити, що вам знадобиться якийсь маркер завершення запиту, який ви могли отримати при запуску запиту, потім скористайтеся, щоб пізніше запитати сервер про запит через інше з'єднання. По суті, вам доведеться реалізувати асинхронні / фонові запити. Можливо, приємна функція, але наразі не підтримується.

Якщо запит надійшов автоматично, або якщо ваш запит був COMMITу польоті в той момент, коли ви вбили клієнта / втратили з’єднання, можлива транзакція у невизначеному стані, коли клієнт не знає, чи не вчинено. Немає реального способу дізнатися, крім пошуку наслідків транзакції на дані.

Якщо це неприпустимо, ви можете скористатися двома фазовими фіксаціями та менеджером транзакцій на стороні клієнта.


1
Вау, саме те, що я шукав, відмінна детальна відповідь! Дякую @Craig_Ringer!
Роб Беднарк


2

Він буде продовжувати працювати, поки не спробує повернути рядки до з'єднання та не виявить обрив. Отже, для запиту, який виконує всю роботу перед поверненням будь-яких рядків, він по суті працюватиме до завершення.


Дякую @jjanes. Чи можете ви вказати на будь-яку документацію або вихідний код, який це вказує?
Роб Беднарк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.