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

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.