У меня есть бэкэнд-процесс, который поддерживает состояние в базе данных PostgreSQL, которая должна быть видимой для внешнего интерфейса. Я хочу:
Правильно обращаться с остановленным и запущенным бэкэндом. Это само по себе так же просто, как очистка таблиц состояний бэкэнда при запуске.
Предохранять от нескольких случаев, когда бэкенд топтал друг друга. Должен быть только один внутренний процесс, но если я случайно запускаю второй экземпляр, я хочу убедиться, что либо первый экземпляр уничтожен, либо второй экземпляр заблокирован до тех пор, пока не исчезнет первый экземпляр.
Решения, которые я могу придумать, включают:
Используйте тот факт, что мой бэкэнд-процесс прослушивает порт. Если попытаться запустить второй экземпляр процесса, произойдет сбой с «Адрес уже используется». Я просто должен убедиться, что он выполняет шаг listen
перед подключением к базе данных и удалением таблиц состояний.
Откройте вторичное соединение и выполните следующее:
BEGIN;
LOCK TABLE initech.backend_lock IN EXCLUSIVE MODE;
Примечание: причина для IN EXCLUSIVE MODE
заключается в том, что LOCK
по умолчанию работает в режиме блокировки AccessExclusive. Это конфликтует с блокировкой AccessShare, полученной pg_dump
.
Не коммит. Оставьте таблицу заблокированной, пока программа не умрет.
Какой хороший шаблон для поддержки одноэлементного внутреннего процесса, который поддерживает состояние в базе данных PostgreSQL? В идеале я бы получил блокировку на время соединения, но LOCK TABLE нельзя использовать вне транзакции.
Фон
Рассмотрим приложение с «посредническим» процессом, который обращается к базе данных и принимает подключения от клиентов. Каждый раз, когда клиент подключается, процесс посредника добавляет запись для него в базу данных. Это обеспечивает два преимущества:
Интерфейс может запросить базу данных, чтобы узнать, какие клиенты подключены.
Когда строка изменяется в другой таблице с именем initech.objects
, и клиенты должны знать об этом, я могу создать триггер, который генерирует список клиентов для уведомления об изменениях, записывает его в таблицу, затем использует NOTIFY, чтобы разбудить процесс посредника.
Без таблицы подключенных клиентов приложение должно выяснить, о каких клиентах следует уведомлять. В моем случае это оказалось довольно грязно: сохраняйте копию таблицы initech.objects
в памяти, и при каждом изменении строки отправляйте старую строку и новую строку обработчикам, которые проверяют, изменилась ли строка, и действуют ли ее сделал. Чтобы сделать это эффективно, необходимо создать «индексы» как для таблицы, хранящейся в памяти, так и для обработчиков, заинтересованных в изменениях строк. Я делаю плохую копию возможностей индексации и запросов SQL в программе брокера. Я бы предпочел перенести эту работу в базу данных.
Итак, я хочу, чтобы процесс посредника поддерживал часть своего состояния в базе данных. Это значительно упрощает рассылку изменений конфигурации клиентам, но требует одновременного подключения только одного экземпляра посредника к базе данных.