Back to questions
Senior
3
Задача на PostgreSQL: несколько воркеров читают задачи из таблицы и генерируют промокоды. Как избежать дублирования работы?
Companies where asked
Магнит Тех
Answer from AI
sobes.tech AI
Чтобы несколько воркеров безопасно читать задачи из таблицы и генерировать промокоды без дублирования, нужно обеспечить, что каждая задача будет обработана ровно одним воркером. В PostgreSQL для этого часто используют транзакции с блокировкой строк.
Основной подход — использовать SELECT ... FOR UPDATE SKIP LOCKED:
- Воркеры выбирают задачи, которые ещё не обработаны, блокируя их для себя:
BEGIN;
SELECT * FROM tasks
WHERE status = 'pending'
FOR UPDATE SKIP LOCKED
LIMIT 1;
-
После выбора задачи воркер помечает её как "в обработке" или сразу генерирует промокод и обновляет статус.
-
Коммит транзакции.
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()
}
}
Таким образом, каждый воркер получает уникальную задачу без пересечений.