Перейти к основному содержимому

Фоновые рабочие процессы

примечание

Эта страница переведена при помощи нейросети GigaChat.

PostgreSQL может быть расширен для запуска пользовательского кода в отдельных процессах. Такие процессы запускаются, останавливаются и контролируются postgres, что позволяет им иметь время жизни, тесно связанное со статусом сервера. Эти процессы подключены к области разделяемой памяти PostgreSQL и имеют возможность подключения к базам данных внутри. Они также могут выполнять несколько транзакций последовательно, как обычный серверный процесс, подключенный клиентом. Кроме того, путем привязки к libpq они могут подключаться к серверу и вести себя как обычное клиентское приложение.

Предупреждение

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

Фоновые рабочие процессы могут быть инициализированы во время запуска PostgreSQL путем включения имени модуля в shared_preload_libraries. Модуль, желающий запустить фоновую рабочую программу, может зарегистрировать ее, вызвав RegisterBackgroundWorker(BackgroundWorker *worker) из своей функции _PG_init(). Фоновые рабочие процессы также могут быть запущены после того, как система будет запущена и работать, вызывая RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle). В отличие от RegisterBackgroundWorker, который можно вызвать только из процесса postmaster, RegisterDynamicBackgroundWorker должен вызываться из обычного бэкенда или другого фонового рабочего процесса.

Структура BackgroundWorker определена следующим образом:

typedef void (*bgworker_main_type)(Datum main_arg);
typedef struct BackgroundWorker
{
char bgw_name[BGW_MAXLEN];
char bgw_type[BGW_MAXLEN];
int bgw_flags;
BgWorkerStartTime bgw_start_time;
int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */
char bgw_library_name[MAXPGPATH];
char bgw_function_name[BGW_MAXLEN];
Datum bgw_main_arg;
char bgw_extra[BGW_EXTRALEN];
pid_t bgw_notify_pid;
} BackgroundWorker;

bgw_name и bgw_type – это строки, которые будут использоваться в сообщениях журнала, списках процессов и аналогичных контекстах. bgw_type должно быть одинаковым для всех фоновых рабочих процессов одного типа, чтобы их можно было сгруппировать, например, в списке процессов. С другой стороны, bgw_name может содержать дополнительную информацию о конкретном процессе. Обычно строка для bgw_name каким-то образом содержит тип, но это строго не требуется.

bgw_flags представляет собой побитовую маску, указывающую на возможности, которые хочет получить модуль. Возможные значения включают:

  • BGWORKER_SHMEM_ACCESS – запрашивает доступ к общей памяти. Этот флаг обязателен.
  • BGWORKER_BACKEND_DATABASE_CONNECTION – запрашивает возможность установления соединения с базой данных, через которое позже можно будет выполнять транзакции и запросы. Фоновый рабочий процесс, использующий BGWORKER_BACKEND_DATABASE_CONNECTION для подключения к базе данных, также должен подключить общую память с помощью BGWORKER_SHMEM_ACCESS, иначе запуск рабочего процесса завершится неудачно.

bgw_start_time – состояние сервера во время которого postgres должно начать процесс; оно может быть одним из следующих значений: BgWorkerStart_PostmasterStart (начать сразу после того, как сам postgres завершил свою собственную инициализацию; процессы, запрашивающие этот параметр, не имеют права на подключение к базам данных), BgWorkerStart_ConsistentState (начинать сразу же, как только достигнуто согласованное состояние в горячем резерве, что позволяет процессам подключаться к базам данных и выполнять запросы только для чтения) и BgWorkerStart_RecoveryFinished (начинать сразу же, как только система перейдет в нормальное состояние чтения-записи). Обратите внимание, что последние два значения эквивалентны на сервере, который не является горячим резервом. Обратите внимание, что эта настройка указывает лишь на то, когда должны быть запущены процессы; они не останавливаются при достижении другого состояния.

bgw_restart_time – интервал в секундах, который postgres должен подождать перед перезапуском процесса в случае его сбоя. Это может быть любое положительное значение или BGW_NEVER_RESTART, указывающее не перезапускать процесс в случае сбоя.

bgw_library_name – имя библиотеки, в которой следует искать начальную точку входа для фонового рабочего. Названная библиотека будет динамически загружена рабочим процессом, и bgw_function_name будет использоваться для идентификации вызываемой функции. Если вызывается функция в основном коде, она должна быть установлена в "postgres".

bgw_function_name – имя функции, используемой в качестве начальной точки входа для нового фонового рабочего. Если эта функция находится в динамически загружаемой библиотеке, она должна быть помечена как PGDLLEXPORT (и не как static).

bgw_main_arg – аргумент Datum для основной функции фонового рабочего процесса. Эта основная функция должна принимать один аргумент типа Datum и возвращать void. В качестве аргумента будет передан bgw_main_arg. Кроме того, глобальная переменная MyBgworkerEntry указывает на копию структуры BackgroundWorker, переданную во время регистрации; рабочему процессу может быть полезно изучить эту структуру.

В Windows (и везде, где EXEC_BACKEND определен) или в динамических фоновых рабочих процессах небезопасно передавать Datum по ссылке, только по значению. Если требуется аргумент, безопаснее всего передать int32 или другое небольшое значение и использовать его в качестве индекса в массиве, выделенном в общей памяти. Если передается значение типа cstring или text, то указатель не будет действителен для нового фонового рабочего процесса.

bgw_extra может содержать дополнительные данные, которые должны быть переданы фоновому рабочему процессу. В отличие от bgw_main_arg, эти данные не передаются в качестве аргумента основной функции рабочего процесса, но к ним можно получить доступ через MyBgworkerEntry, как обсуждалось выше.

bgw_notify_pid - это PID процесса бэкенда PostgreSQL, которому постмастер должен отправить SIGUSR1 при запуске процесса или выходе из него. Он должен быть равен нулю для работников, зарегистрированных во время запуска постмастера, или когда бэкенд, регистрирующий работника, не желает ждать запуска работника. В противном случае он должен быть инициализирован до MyProcPid.

После запуска процесс может подключиться к базе данных, вызвав BackgroundWorkerInitializeConnection(char *dbname, char *username, uint32 flags) или BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags). Это позволяет процессу выполнять транзакции и запросы с использованием интерфейса SPI. Если dbname имеет значение NULL или dboid равно InvalidOid, сеанс не подключен ни к какой конкретной базе данных, но могут быть доступны общие каталоги. Если username имеет значение NULL или useroid равно InvalidOid, процесс будет выполняться от имени суперпользователя, созданного во время initdb. Если BGWORKER_BYPASS_ALLOWCONN указан как flags, возможно обойти ограничение подключения к базам данных, не допускающим пользовательских соединений. Фоновый рабочий процесс может вызвать одну из этих двух функций, и только один раз. Невозможно переключаться между базами данных.

Сигналы изначально блокируются при достижении основной функции фонового рабочего процесса и должны быть разблокированы им; это позволяет процессу настроить свои обработчики сигналов, если необходимо. Сигналы могут быть разблокированы в новом процессе путем вызова BackgroundWorkerUnblockSignals и заблокированы вызовом BackgroundWorkerBlockSignals.

Если bgw_restart_time для фонового рабочего процесса настроен как BGW_NEVER_RESTART, или если он завершает работу с кодом выхода 0 или завершается из-за TerminateBackgroundWorker, то он будет автоматически отменен постмастером при выходе. В противном случае он будет перезапущен после периода времени, настроенного через bgw_restart_time, или немедленно, если постмастер повторно инициализирует кластер из-за сбоя бэкенда. Бэкенды, которым нужно временно приостановить выполнение, должны использовать прерывающийся сон вместо завершения работы; это можно сделать, вызвав WaitLatch(). Убедитесь, что установлен флаг WL_POSTMASTER_DEATH, когда вызывается эта функция, и проверьте код возврата для немедленного выхода в экстренном случае, когда сам postgres завершился.

Когда фоновый рабочий процесс регистрируется с использованием функции RegisterDynamicBackgroundWorker, существует возможность для бэкенда, выполняющего регистрацию, получить информацию о состоянии рабочего процесса. Бэкенды, желающие сделать это, должны передать адрес BackgroundWorkerHandle * в качестве второго аргумента к RegisterDynamicBackgroundWorker. Если рабочий процесс успешно зарегистрирован, этот указатель будет инициализирован непрозрачным дескриптором, который впоследствии может быть передан к GetBackgroundWorkerPid(BackgroundWorkerHandle *, pid_t *) или TerminateBackgroundWorker(BackgroundWorkerHandle *). GetBackgroundWorkerPid может использоваться для опроса состояния рабочего процесса: возвращаемое значение BGWH_NOT_YET_STARTED указывает на то, что рабочий процесс еще не был запущен постмастером; BGWH_STOPPED указывает, что он был запущен, но больше не работает; а BGWH_STARTED указывает, что он в данный момент выполняется. В последнем случае PID также будет возвращен через второй аргумент. TerminateBackgroundWorker заставляет постмастер отправить SIGTERM рабочему процессу, если он работает, и отменить его регистрацию сразу же, как только он перестанет работать.

В некоторых случаях процесс, который регистрирует фонового рабочего, может захотеть дождаться запуска рабочего процесса. Это можно сделать, установив bgw_notify_pid равным MyProcPid и затем передав BackgroundWorkerHandle *, полученный во время регистрации, функции WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *). Эта функция будет блокироваться до тех пор, пока постмастер не попытается запустить фонового рабочего, или пока постмастер не умрет. Если фоновое задание выполняется, возвращаемым значением будет BGWH_STARTED, и PID будет записан по предоставленному адресу. В противном случае возвращаемое значение будет равно BGWH_STOPPED или BGWH_POSTMASTER_DIED.

Процесс также может ожидать завершения фонового рабочего процесса с использованием функции WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle) и передачи BackgroundWorkerHandle *, полученного при регистрации. Эта функция будет заблокирована до тех пор, пока фоновый рабочий процесс не завершит работу или постмастер не умрет. Когда фоновый рабочий процесс завершает работу, возвращаемое значение равно BGWH_STOPPED, если постмастер умирает, он вернет BGWH_POSTMASTER_DIED.

Фоновые рабочие процессы могут отправлять асинхронные уведомления, либо используя команду NOTIFY через SPI, либо непосредственно через Async_Notify(). Такие уведомления будут отправляться при фиксации транзакции. Фоновым рабочим процессам не следует регистрироваться для получения асинхронных уведомлений с помощью команды LISTEN, поскольку нет инфраструктуры для того, чтобы рабочий процесс потреблял такие уведомления.

Модуль src/test/modules/worker_spi содержит рабочий пример, который демонстрирует некоторые полезные методы.

Максимальное количество зарегистрированных фоновых рабочих процессов ограничено параметром max_worker_processes.