Sobes.tech
Back to questions
Senior
3

Задача на PostgreSQL: несколько воркеров читают задачи из таблицы и генерируют промокоды. Как избежать дублирования работы?

Companies where asked
Магнит Тех

Answer from AI

sobes.tech AI

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

Основной подход — использовать SELECT ... FOR UPDATE SKIP LOCKED:

  1. Воркеры выбирают задачи, которые ещё не обработаны, блокируя их для себя:
BEGIN;
SELECT * FROM tasks
WHERE status = 'pending'
FOR UPDATE SKIP LOCKED
LIMIT 1;
  1. После выбора задачи воркер помечает её как "в обработке" или сразу генерирует промокод и обновляет статус.

  2. Коммит транзакции.

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

Пример на Go с использованием базы:

func worker(db *sql.DB) {
  for {
    tx, _ := db.Begin()
    row := tx.QueryRow(`
      SELECT id FROM tasks
      WHERE status = 'pending'
      FOR UPDATE SKIP LOCKED
      LIMIT 1
    `)

    var taskID int
    err := row.Scan(&taskID)
    if err == sql.ErrNoRows {
      tx.Rollback()
      break // Нет задач
    }

    // Генерируем промокод и обновляем задачу
    promoCode := generatePromoCode()
    _, err = tx.Exec(`
      UPDATE tasks SET status = 'done', promo_code = $1 WHERE id = $2
    `, promoCode, taskID)

    if err != nil {
      tx.Rollback()
      continue
    }

    tx.Commit()
  }
}

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