Xpoint
   [напомнить пароль]

Повисшая транзакция в Postgres

Метки: [без меток]
2006-10-03 09:53:27 [обр] Дмитрий Кононов(0/16)[досье]

Всех приветствую.

Работаю с pgsql 8.1.4.
Запускаю транзакцию, которая изменяет некоторые строки в таблице.
Код выглядит примерно так:

$db->begin();
$res = $db->execute("INSERT INTO mytable (id, num, str, ts) VALUES (125, 1, 'str1', now())");
echo "waiting 10 seconds...\n";
sleep(10);
$db->execute("UPDATE mytable SET num = num+1 WHERE id=1");
$db->end();

Во время sleep-а скрипта обрываю подключение к бд, а потом убиваю скрипт.
Скрипт умирает, но процесс, обрабатывающий транзакцию остается работать на сервере в режиме "idle" 2 часа, при этом остаются заблокированными записи, которые начала править повисшая транзакция.
Это приводит к тому, что новая транзакция на тех же данных ждет время, указанное в statement_timeout. (по умолчанию - бесконечно)
Как сие разрулить?

Порылся в документации и нашел системную таблицу pg_locks, в которой хранится список текущих блокировок. К сожалению, там не указывается, с какого момента началась та или иная блокировка.
Для этого создается отдельная таблица примерно такой структуры:

pidxidts
1045161082006-09-01 19:01:09

где pid и xid - pid процесса и id транзакции, которая ожидает,
ts - с какого времени началась транзакция.

Далее каждую минуту в кроне читаем pg_locks, собираем инфу о начавшихся транзакциях и обновляем вышеописанную таблицу.
Как только ts достигла какого-то значения, посылаем процессу SIGTERM.

Думается, что существует какое-то стандартное решение, но я его не нашел.

Или можно ли как-то штатно изменить время ожидания процесса?
В конфигах ничего нет.

спустя 9 часов [обр] Дмитрий Кононов(0/16)[досье]

Порыл еще мануалы, нашел, что если включить stats_command_string, то в системной вьюхе pg_stat_activity появляется время начала запроса и его текущий статус.
Таким образом, свою таблицу создавать не надо, достаточно выполнить запрос вида:
SELECT procpid AS pid, EXTRACT(EPOCH FROM (now()-query_start))::integer AS duration
FROM pg_stat_activity
WHERE current_query='<IDLE> in transaction';

Задача упрощается, но все равно как-то через одно место.
Есть идеи?

спустя 8 дней [обр] Дмитрий Кононов(0/16)[досье]
Никто с таким не сталкивался?
Ни у кого что ли транзакция не рвалась посредине?
Powered by POEM™ Engine Copyright © 2002-2005