Шаблон для одноэлементного процесса приложения с использованием базы данных - PullRequest
1 голос
/ 29 декабря 2011

У меня есть бэкэнд-процесс, который поддерживает состояние в базе данных 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 в программе брокера. Я бы предпочел перенести эту работу в базу данных.

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

Ответы [ 2 ]

2 голосов
/ 29 декабря 2011

это можно сделать с помощью консультативных замков

http://www.postgresql.org/docs/9.1/interactive/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS

0 голосов
/ 13 мая 2014

Я решил это сегодня так, как мне показалось, лаконично:

CREATE TYPE mutex as ENUM ('active');
CREATE TABLE singleton (status mutex DEFAULT 'active' NOT NULL UNIQUE);

Затем ваш бэкэнд-процесс пытается сделать это:

insert into singleton values ('active');

И выходит или ждет, если этого не произойдет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...