использовать базу данных как очередь задач - PullRequest
0 голосов
/ 29 апреля 2018

В одном из наших java-приложений (основанных на postgresql db) у нас есть таблица базы данных, в которой содержится список задач, которые должны быть выполнены. В каждой строке есть блоб json для подробной информации о задаче, а также запланированное значение времени.

У нас есть несколько работников / потоков java, чьи задания заключаются в поиске задач, готовых к выполнению (на основе значения расписания), выполнении и удалении их из таблицы. Выполнение задачи может занять несколько секунд.

Проблема в том, что несколько работников могут захватить одну и ту же строку, что приведет к дублированию выполнения задачи, чего мы хотим избежать.

Один из подходов заключается в том, что при выполнении операции select для захвата строки используйте FOR UPDATE, чтобы заблокировать строку, предположительно не позволяя другому работнику захватить ту же строку, которая заблокирована.

Меня беспокоит этот подход: строка блокируется только при выполнении транзакции select в БД (согласно this ), в то время как код Java фактически выполняет строку / задачу выбрана, блокировка снята, другой работник может снова ее захватить.

Могут ли некоторые пролить свет на то, сработает ли вышеуказанный подход наверняка? Спасибо!

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

Когда один поток успешно заблокировал строку в данном соединении, другой, пытающийся получить блокировку строки в другом соединении, должен потерпеть неудачу. Вы должны выполнить команду select-for-update с некоторым предложением no-wait , чтобы запросить немедленный сбой, если строка заблокирована.

Теперь это не решает запрос против гонки блокировок, поскольку неудачная блокировка может прервать выполнение потока. Вы можете решить это с помощью (в каждом исполнении):

  1. Выбрать все записи с новыми задачами (независимо от того, обрабатываются они или нет)
  2. Для каждой новой задачи, возвращенной в [1], запустите соответствующий выбор для обновления, а затем продолжите обработку задачи, если блокировка не удалась.
  3. Если попытка блокировки не удалась, пропустите задачу, не завершив весь процесс.
0 голосов
/ 29 апреля 2018

Относитесь к вызовам БД как к элементарным инструкциям и проектируйте бесплатные алгоритмы блокировки вокруг вашей таблицы, используя обновления для изменения логического столбца «в процессе» с false на true. Также может быть просто state int (0 = в наличии, 1 = в процессе, N = код результата).

Убедитесь, что у вас есть частичный индекс для состояния 0 (и, возможно, 1 для восстановления после сбоев для поиска выполняемых задач), чтобы ...where state=0 оставался избирательным и быстрым (помимо запланированного индекса времени, конечно).

Надеюсь, это поможет.

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