2016-12-01 3 views
1

Я пишу скалярную функцию plpgsql, которая содержит функцию C, которая имеет побочный эффект вне базы данных. Когда функция вызывается, в некоторых произвольных SQL (триггер, выбор, запись и т. Д.), Я хочу, чтобы побочный эффект был зафиксирован или откат на границе работы PostgreSQL (UOW). Я могу обрабатывать фиксацию UOW, но я не знаю, как «поймать» ROLLBACK базы данных и откатить побочный эффект. Ключевым моментом является то, что я пишу функцию, но не контролирую, как она называется, т. Е. Я не могу «заставить» вызов быть в блоке с обработчиками EXCEPTION. Есть идеи?Как поймать PostgreSQL ROLLBACK для функции с побочными эффектами UOW?

Для фиксации я планирую включить функцию INSERT plpsql в базу данных TABLE, которая имеет триггер «... ПОСЛЕ ВСТАВКИ ... ВЫПОЛНИТЬ ПРОЦЕДУЮ commit_my_side_effect()», поэтому, когда UOW зафиксировано, строка совершенное, срабатывание триггера AFTER INSERT и престо, побочный эффект совершен;

Единственная идея, которую я имею до сих пор, - это передать txid_current() фоновому рабочему процессу. Затем, при некотором сердцебиении, использующем SPI, проверьте, не находится ли txid в полете или совершено, тогда его, должно быть, отбросили назад. Но это похоже на тяжелый подъем.

ответ

0

В целом, транзакция считается «откатанной», если она не совершена, и она больше не работает; в интересах соответствия ACID, явный ROLLBACK должен быть функционально идентичен тому, как тянуть шнур питания на вашем сервере, поэтому в целом не может быть преднамеренного действия, связанного с откатом, с которым вы могли бы подключиться.

Фактическое удаление откатных данных обрабатывается vacuuming, который работает более или менее как ваш предлагаемый фоновый работник: все, что написано в транзакции, которая не работает и не совершена, является кандидатом на удаление. Тем не менее, это немного больше, чем транзакция, поскольку транзакция, содержащая субтранзакции (SAVEPOINT s или PL/pgSQL EXCEPTION), может быть частично откат. Другими словами, одного только txid_current() недостаточно, чтобы решить, было ли совершено изменение, и я не знаю, предоставляет ли Postgres достаточную информацию о состояниях субтранзакций, чтобы позволить вам удовлетворить это.

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

  • Пусть ваш PL/функция PGSQL вставки в рабочей очередь, которая опрашивается внешним процессом, или
  • Кормовых изменений в процесс через NOTIFY (уведомления только произнесенную фиксацию, и уведомление от откатываемых subtransactions отбрасывается)

уведомление более легкое и нижняя задержка (они доставлены в асинхронном режиме, поэтому нет опроса не требуется), но менее надежное, чем подход таблицы на основе, в качестве уведомления очередь вырывается в случае сбоя или неожиданного отключения п. Конечно, если вы хотите безопасности при столкновении без ошибок опроса, вы можете просто сделать то и другое.

+0

Спасибо, Nick, NOTIFY на КАНАЛЕ - отличное предложение, но оно не позволяет боковому эффекту стрелять в нужное время. –

0

Я нашел функцию ON_ERROR_ROLLBACK и посмотрел на реализацию, https://github.com/postgres/postgres/blob/master/src/bin/psql/common.c, я думаю, что могу «обернуть» все команды SQL, используя следующий псевдокод, чтобы добавить «поддельную» точку сохранения и «поддельный» откат в точку сохранения и выстрелить "rollback_side_effect()":

side_effect_fired = false; // set true if the side_effect udf called 
run("SAVEPOINT _savepoint"); 
run($sqlcommand); 
if (txn_status == ERROR && side_effect_fired) { 
    run("ROLLBACK TO _savepoint" 
    rollback_side_effect()); // rollback the side effect 
} 

я, вероятно, нужен стек _savepoint. Я побегу с этим!

Смежные вопросы