Шаблон для однопользовательского процесса приложения с использованием базы данных

1 Joey Adams [2011-12-29 07:03:00]

У меня есть бэкэнд-процесс, который поддерживает состояние в базе данных PostgreSQL, которое должно быть видимым для интерфейса. Я хочу:

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

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

Решения, о которых я могу думать, включают:

  • Используйте тот факт, что мой серверный процесс прослушивает порт. Если второй экземпляр процесса пытается начать, он не сработает с "Адресом, который уже используется". Я просто должен убедиться, что он выполняет шаг listen перед подключением к базе данных и уничтожением таблиц состояний.

  • Откройте дополнительное соединение и выполните следующее:

    BEGIN;
    LOCK TABLE initech.backend_lock IN EXCLUSIVE MODE;
    

    Примечание. Причина IN EXCLUSIVE MODE заключается в том, что LOCK умолчанию установлен в режим блокировки AccessExclusive.Это конфликтует с блокировкой AccessShare, полученной pg_dump.

    Не совершайте. Оставьте таблицу заблокированной до тех пор, пока программа не умрет.

Какая хорошая модель для поддержки одного backend-процесса, поддерживающего состояние в базе данных PostgreSQL? В идеале я бы приобрел блокировку на время соединения, но LOCK TABLE не может использоваться за пределами транзакции.

Задний план

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

  • Интерфейс может запрашивать базу данных, чтобы узнать, какие клиенты подключены.

  • Когда строка изменяется в другой таблице с именем initech.objects, и клиенты должны знать об этом, я могу создать триггер, который генерирует список клиентов, чтобы уведомлять об изменении, записывать его в таблицу, а затем использовать NOTIFY для пробуждения брокерский процесс.

    Без таблицы подключенных клиентов приложение должно выяснить, какие клиенты уведомлять. В моем случае это оказалось довольно запутанным: сохраните копию таблицы initech.objects в памяти, и в любой момент, когда строка изменится, initech.objects старые строки и новую строку обработчикам, которые проверяют, изменилась ли строка и действовала ли она сделал. Для этого эффективно создавать "индексы" как для хранимой таблицы, так и для обработчиков, заинтересованных в изменениях строк. Я делаю плохую копию SQL-индексирования и запросов в программе брокера. Я предпочел бы переместить эту работу в базу данных.

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

postgresql


2 ответа


2 Решение Pavel Stehule [2011-12-29 16:18:00]

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

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


0 user2409824 [2014-05-13 18:34:00]

Я решил это сегодня так, как я думал, был кратким:

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

Затем ваш внутренний процесс пытается это сделать:

insert into singleton values ('active');

И завершает работу или ждет, если это не удастся.