parsed - 0 - страница еще не спаршена, 1 - страница спаршена.
Не так.
NULL - не парсилась.
0 - парсинг выполнен.
>0 - взято на парсинг соединением (функция
CONNECTION_ID()) номер N.
Соответственно попробовать зарезервировать запись на парсинг:
UPDATE urls
SET parsed = CONNECTION_ID()
WHERE parsed IS NULL
ORDER BY datetime_added LIMIT 1;
Получить зарезервированную запись и начать её парсинг:
SELECT *
FROM urls
WHERE parsed = CONNECTION_ID();
Если вернётся более одной записи - в системе большие проблемы, надо звать администратора задачи. Если пустой набор - значит, запись перехватили, пробуем резервировать заново (тоже, кстати, повод позвать админа задачи - так не должно быть). Иначе - парсим полученную запись.
По окончании парсинга соответственно
UPDATE urls
SET parsed = 0
WHERE parsed = CONNECTION_ID();
Ну и периодически выполняется event procedure, который находит записи, формально помеченные как обрабатываемые, но, судя по времени, обработчик подвис. Такие записи возвращаются на обработку
CREATE EVENT clear_parsing_flag
ON SCHEDULE EVERY 1 MINUTE
DO
UPDATE urls
SET parsed = NULL
WHERE parsed > 0
-- считаем, что 5 минут более чем достаточно
AND datetime_start_parsed < CURRENT_TIMESTAMP - INTERVAL 5 MINUTE;
Само собой никаких пулов соединений, никаких открыть-закрыть - все операции выполняются в рамках одного persistent connection. Автовосстановление соединения при обрыве также запрещено.
Если соединение развалилось, неважно по какой причине, бросаем обрабатываемую запись (шедулер вернёт её в необработанные), соединяемся заново и начинаем с самого начала, с резервирования.
Ну и предусмотреть случай, когда записей на парсинг просто нет. Например, если 5 резервирований подряд не смогли получить запись на обработку, то, чтобы не ставить сервер раком, вводим между попытками резервирования задержку, например, на 5 секунд... ну и вываливаем баннер, что, походу, парсить нечего.