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

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.