Как предотвратить двойную обработку одной строки из базы?
Синьоры и синьориты, приветствую.
Есть таблица в БД (условно):
Название Время обработки
Строка 1 10:00
Строка 2 10:01
Строка 3 10:02
............................
Строка N 23:59
Есть условно 10 скриптов, одновременно запускающихся по крону.
10 скриптов это 10 одинаковых PHP файлов, которые отличаются только авторизационными данными.
Все 10 скриптов в процессе работы обращаются к этой таблице.
Каждый берет самую "несвежую строку". В нашем случае ту, которая была обработана в 10:00.
После этого устанавливает ей текущую дату/время в колонку "Время обработки", обрабатывает.
После обработки возвращается в эту же таблицу и опять по новой.
Основная задача - обеспечить минимальный интервал между обращениями к каждой строке.
Вариант, когда на каждый скрипт своя часть таблицы не подходит - если условно "банят аккаунт", через который авторизуется скрипт - часть таблицы не будет обработана.
Будем считать скрипты демонами, работающими постоянно.
Время обработки одной строки всегда различно.
Ситуация, когда 2 скрипта обратятся к одной строке более чем возможна.
И между двумя запросами SELECT и UPDATE в любом случае пройдет какое-то время.
Как не допустить ситуации, когда несколько скриптов одновременно обратились к одной и той же строке таблицы и взяли ее в работу?
В результате такого поведения задублируется информация в месте, куда отрабатывает скрипт, чего никак нельзя допустить.
P. S. Я знаю, что ничего не знаю. Знаю, что так делать неправильно. Знаю, что мои познания в архитектуре болтаются около нуля.
Но я хочу решить именно эту задачу наиболее эффективно.
Я читаю книги и учу матчасть.
Если хотите уведомить меня о том, что мне лучше бросить программирование и ничего сюда не писать - не тратьте время.
Команда LOCK TABLES блокирует указанные в ней таблицы для данного потока
новый скрипт = новый поток, как я понимаю.
Поэтому увы, этот вариант не подходит.
Если бы был вариант блокировать таблицу на уровне mysql сервера, то да.
Но насколько знаю такого нет.
нужно писать уникальный ИД и по нему выбирать строку.
Т.е.
1. в скрипте генерируете хэш
2. делаете апдейт с этим хэшем
3. по этому хэшу уже берете строку и отрабатываете.
Виталий Хоменко, По-моему единственный вариант при отсутствии локов. Чего подсматривать, как-то нужно было сделать, вот и сделал. Ничего сложного тут нет.
Предположительно у вас таблица содержит задачи в формате:
id | execute_in | executed_at
1 | 10:00 | null
2 | 10:01 | null
Так вот чтобы выбрать на языке postgresql, можно выполнить следующий запрос
UPDATE jobs SET executed_at = now() WHERE id = (SELECT id FROM jobs WHERE execute_in <= now() AND executed_at is null LIMIT 1) AND executed_at is null RETURNING id
Тем самым мы обновляем только одну запись и после ее обновления получаем еë id, или всю запись