Sobes.tech
Senior

10 verwerkende applicaties halen voortdurend taken uit de database en verwerken ze. Hoe voorkom je dat twee exemplaren van de applicatie hetzelfde taak oppakken?

sobes.tech AI

Antwoord van 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 *;

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

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