Фоновые рабочие процессы
QHB может быть расширена для запуска пользовательского кода в отдельных процессах. Такие процессы запускаются, останавливаются и контролируются QHB, что позволяет им тесно связать время жизни со статусом сервера. Эти процессы имеют возможность подключаться к области общей памяти QHB и подключаться к базам данных, они также могут запускать последовательно, несколько транзакций как обычный серверный процесс, подключенный к клиенту. Также, связываясь с libpq, они могут подключаться к серверу и вести себя как обычное клиентское приложение.
Фоновые процессы могут быть инициализированы во время запуска QHB путем включения имени модуля в 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[BGW_MAXLEN];
char bgw_function_name[BGW_MAXLEN];
Datum bgw_main_arg;
char bgw_extra[BGW_EXTRALEN];
int bgw_notify_pid;
} BackgroundWorker;
bgw_name и bgw_type - это строки, которые будут использоваться в сообщениях журнала, списках процессов и в подобных контекстах. bgw_type должен быть одинаковым для всех фоновых процессов одного типа, чтобы, например, можно было сгруппировать таких процессов в список процессов. bgw_name с другой стороны, может содержать дополнительную информацию о конкретном процессе. (Как правило, строка для bgw_name будет как-то идентифицировать фоновый процесс, но это не обязательно.)
bgw_flags - битовая маска или битовая маска, указывающая возможности, которые предоставляются модулю. Возможные значения:
Флаг | Назначение |
---|---|
BGWORKER_SHMEM_ACCESS | Запрашивает доступ к общей памяти. Рабочие, не имеющие доступа к общей памяти, не могут получить доступ ни к одной из общих структур данных QHB, таких как тяжелые или облегченные блокировки, общие буферы, или к любым пользовательским структурам данных, которые рабочий может захотеть создать и использовать. |
BGWORKER_BACKEND_DATABASE_CONNECTION | Запрашивает возможность установить соединение с базой данных, с помощью которого она может позже выполнять транзакции и запросы Фоновый процесс, использующий BGWORKER_BACKEND_DATABASE_CONNECTION для подключения к базе данных, должен также подключить разделяемую память с помощью BGWORKER_SHMEM_ACCESS, иначе запуск рабочего не удастся. |
bgw_start_time - состояние сервера, в течение которого QHB должна запустить процесс - это может быть BgWorkerStart_PostmasterStart (запускаться, как только сама QHB завершила свою собственную инициализацию, процессы, запускающиеся в этот момент, не подходят для соединений с базой данных), BgWorkerStart_ConsistentState (запускаться, как только достигнуто согласованное состояние, что позволяет процессам подключаться к базам данных и выполнять запросы только для чтения) и BgWorkerStart_RecoveryFinished (запускаться, как только система BgWorkerStart_RecoveryFinished перевела систему в нормальное состояние чтения-записи). Обратите внимание, что последние два значения эквивалентны на сервере, который не является standby. Обратите внимание, что этот параметр указывает только, когда фоновые процессы должны запускаться - они не будут останавливаться при переходе в другое состояния.
bgw_restart_time - это интервал в секундах, который QHB должна ждать перед перезапуском процесса в случае его сбоя. Это может быть любое положительное значение или BGW_NEVER_RESTART, указывающее не перезапускать процесс в случае сбоя.
bgw_library_name - это имя библиотеки, в которой следует искать начальную точку входа для фонового процесса. Именованная библиотека будет динамически загружена рабочим процессом, а имя-функции- bgw_function_name будет использоваться для идентификации вызываемой функции. При загрузке функции из основного кода должно быть установлено «QHB».
bgw_function_name - это имя функции в динамически загружаемой библиотеке, которая должна использоваться в качестве начальной точки входа для нового фонового процесса.
bgw_main_arg - это аргумент типа Datum для основной функции фонового процесса. Основная функция должна принимать один аргумент типа Datum и возвращать void. bgw_main_arg будет передан в качестве аргумента. Кроме того, глобальная переменная MyBgworkerEntry указывает на копию структуры BackgroundWorker переданную во время регистрации - процесс запуска может использовать эту структуру.
bgw_extra может содержать дополнительные данные для передачи фоновому процессу. В отличие от bgw_main_arg, эти данные не передаются в качестве аргумента основной функции worker-a, но к ним можно получить доступ через MyBgworkerEntry, как обсуждалось выше.
bgw_notify_pid - это PID бэкэнд-процесса QHB, которому qhbmaster должен отправить SIGUSR1 при запуске или выходе из процесса. Должен быть 0 для процессов, зарегистрированных во время запуска qhbmaster, или когда бэкэнд, регистрирующий процесса, не хочет ждать запуска процесса. В противном случае его следует инициализировать как 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. Если в качестве flags указано BGWORKER_BYPASS_ALLOWCONN можно обойти ограничение для подключения к базам данных, не разрешая пользовательские подключения. Фоновый рабочий может вызвать только одну из этих двух функций и только один раз. Невозможно переключить базы данных.
Сигналы изначально блокируются, когда управление достигает основной функции фонового процесса, и должны быть разблокированы самим процессом - это позволяет процессу при необходимости настраивать свои обработчики сигналов. Сигналы могут быть разблокированы в новом процессе путем вызова BackgroundWorkerUnblockSignals и заблокированы путем вызова BackgroundWorkerBlockSignals .
Если bgw_restart_time для фонового процесса сконфигурировано как
BGW_NEVER_RESTART, или если он завершается с кодом выхода 0 или
завершается TerminateBackgroundWorker, он будет автоматически отменен главным процессом при выходе. В противном случае он будет
перезапущен по истечении периода времени, настроенного с помощью
bgw_restart_time, или немедленно, если qhbmaster повторно
инициализирует кластер из-за сбоя бэкенда. Бэкэнды, которые должны
временно приостановить выполнение, должны использовать паузы
вместо выхода - это может быть достигнуто путем вызова WaitLatch()
.
Убедитесь, что при вызове этой функции установлен флаг
WL_POSTMASTER_DEATH, и проверьте код возврата для быстрого завершения
в аварийном случае, когда сама qhb завершилась.
Когда фоновый процесс зарегистрирован с помощью функции RegisterDynamicBackgroundWorker, сервер, выполняющий регистрацию, может получить информацию о статусе процесса. Бэкэнды, желающие сделать это, должны передать адрес BackgroundWorkerHandle * в качестве второго аргумента RegisterDynamicBackgroundWorker. Если процесс успешно зарегистрирован, этот указатель будет инициализирован с непрозрачным дескриптором, который впоследствии может быть передан в GetBackgroundWorkerPid( BackgroundWorkerHandle *, pid_t * ) или TerminateBackgroundWorker( BackgroundWorkerHandle * ) . GetBackgroundWorkerPid может использоваться для опроса статуса процесса: возвращаемое значение BGWH_NOT_YET_STARTED указывает, что процесс еще не был запущен qhbmaster - BGWH_STOPPED указывает, что он был запущен, но больше не работает и BGWH_STARTED указывает, что он в данный момент работает. В этом последнем случае PID также будет возвращен через второй аргумент. TerminateBackgroundWorker заставляет qhbmaster отправлять SIGTERM процессу, если он работает, и отменять его регистрацию, как только он завершится.
В некоторых случаях процесс, который регистрирует фоновый процесс, может дождаться его запуска. Это может быть достигнуто путем инициализации bgw_notify_pid для MyProcPid и последующей передачи BackgroundWorkerHandle * полученного во время регистрации, в WaitForBackgroundWorkerStartup( BackgroundWorkerHandle *handle, pid_t * ). Эта функция будет блокироваться до тех пор, пока qhbmaster не попытается запустить фоновый процесс снова, или пока qhbmaster не прекратит работу. Если фоновый процесс работает, возвращаемое значение будет BGWH_STARTED, а PID будет записан по указанному адресу. В противном случае возвращаемое значение будет BGWH_STOPPED или BGWH_POSTMASTER_DIED .
Процесс также может ожидать выключения фонового процесса, используя WaitForBackgroundWorkerShutdown( BackgroundWorkerHandle *handle ) и передавая BackgroundWorkerHandle * полученный при регистрации. Эта функция будет блокироваться до тех пор, пока не завершится фоновый процесс или qhbmaster не завершит работу. Когда фоновый процесс завершает работу, возвращаемое значение будет BGWH_STOPPED, если qhbmaster завершится, он вернет BGWH_POSTMASTER_DIED.
Если фоновый процесс отправляет асинхронные уведомления с помощью
команды NOTIFY
через интерфейс программирования сервера SPI
, он
должен явно вызывать ProcessCompletedNotifies после
ProcessCompletedNotifies включающей транзакции, чтобы можно было
доставлять любые уведомления. Если фоновый процесс регистрируется для
получения асинхронных уведомлений с LISTEN через SPI, процесс
регистрирует эти уведомления, но у него нет программного способа
перехватывать и отвечать на эти уведомления.
Максимальное количество зарегистрированных фоновых процессов ограничено
параметров max_worker_processes
.