Sobes.tech
Senior

Вазифа дар PostgreSQL: чанд коргар вазифаҳоро аз рӯйхати маълумот мехонанд ва коди промо тайёр мекунанд. Чӣ тавр аз такроршавии корҳо пешгирӣ кардан мумкин аст?

sobes.tech AI

Ҷавоб аз 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()
  }
}

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