Как логировать статус процедуры в PostgreSQL вне транзакции
При выполнении длительных процедур в PostgreSQL часто возникает проблема: все записи в лог-таблицу, сделанные внутри процедуры, становятся видимыми только после завершения всей транзакции. Это связано с тем, что по умолчанию процедура работает в рамках одной транзакции, и изменения не фиксируются до её окончания. В этой статье мы разберём несколько способов, как выводить промежуточный статус в реальном времени.
Почему данные лога не видны сразу?
PostgreSQL использует механизм транзакционной изоляции. Все операции INSERT, UPDATE или DELETE внутри процедуры являются частью одной транзакции. Другие сессии не видят эти изменения до команды COMMIT. Поэтому, если процедура выполняется 10 минут, все записи в лог появятся только в конце. Это неудобно для мониторинга.
Способы логирования статуса в реальном времени
1. Использование dblink или postgres_fdw
Вы можете подключиться к той же базе данных через отдельное соединение (dblink) или через внешнюю таблицу (postgres_fdw). Это создаст новую сессию и новую транзакцию, независимую от основной. Пример с dblink:
PERFORM dblink_connect('log_conn', 'dbname=mydb');
PERFORM dblink_exec('log_conn', 'INSERT INTO log_table(status) VALUES (''Идёт шаг 1'')');
PERFORM dblink_disconnect('log_conn');Недостаток - требуется настроить расширение и права доступа.
2. Автономные транзакции (pg_background)
Расширение pg_background позволяет выполнять функции в фоновом режиме с собственными транзакциями. Вы запускаете отдельный процесс, который вставляет записи в лог независимо от основной транзакции. Это более производительно, чем dblink, но требует установки расширения.
3. Использование pg_notify и слушателя
Вместо записи в таблицу вы можете отправлять уведомления через pg_notify. Другое приложение (например, демон на Python) слушает канал и пишет в лог уже вне транзакции. Пример:
PERFORM pg_notify('log_channel', 'Шаг 1 выполнен');Этот способ минимально нагружает базу данных и не требует дополнительных прав на запись в таблицу.
Какой способ выбрать?
- Для простого прототипа - используйте dblink.
- Для продакшена с высокой нагрузкой - pg_background или pg_notify.
- Если данные лога нужны в реальном времени - pg_notify с внешним слушателем.
Практические рекомендации
Перед использованием любого метода убедитесь, что у вас есть права на создание расширений. Также помните, что автономные транзакции могут привести к несогласованности данных, если основная транзакция откатится - лог останется. В некоторых случаях это приемлемо, но если требуется строгая согласованность, рассмотрите вариант с отдельной таблицей и ручной очисткой.
Таким образом, проблема вывода текущего статуса из процедуры решается с помощью отдельного соединения, фоновых процессов или уведомлений. Выберите подходящий под вашу архитектуру.