Sobes.tech
Назад к вопросам
Senior
4

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

Компании, где спрашивали
ИП Ганус Александр Андреевич

Ответ от нейросети

sobes.tech AI

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

  1. Блокировка на уровне базы данных (pessimistic locking)

    • Использовать транзакции с блокировкой строк (SELECT ... FOR UPDATE), чтобы при чтении задачи она блокировалась для других приложений.
  2. Оптимистичная блокировка

    • Добавить в таблицу поле версии или метку времени.
    • При попытке взять задачу в работу обновлять это поле с проверкой, что версия не изменилась.
    • Если обновление прошло успешно — задача взята, иначе — кто-то другой уже взял.
  3. Атомарное обновление статуса задачи

    • Выполнить запрос, который одновременно выбирает и помечает задачу как "в работе".
    • Например, UPDATE tasks SET status = 'processing' WHERE status = 'pending' LIMIT 1 RETURNING *.
    • Таким образом, только одно приложение получит задачу.
  4. Использование очередей сообщений

    • Вместо прямого опроса базы использовать очередь (RabbitMQ, Kafka, Redis Streams), где задачи распределяются между потребителями.
  5. Использование распределенных блокировок

    • Например, с помощью Redis (Redlock) или ZooKeeper для координации доступа к задачам.

Пример атомарного обновления в SQL:

UPDATE tasks
SET status = 'processing', worker_id = :workerId
WHERE id = (
  SELECT id FROM tasks WHERE status = 'pending' LIMIT 1
)
RETURNING *;

Это гарантирует, что одна задача будет взята только одним приложением.

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