После выката обходчик должен начать новый круг с главной. Он и начинал — но через минуту очередь «откатывалась» к старому остатку, а главная оставалась холодной. Виновником оказалась особенность WordPress, о которой мало кто помнит: опция, прочитанная в запросе, кэшируется до конца этого запроса.

Это двадцать четвёртая часть цикла «Кэш страниц без MISS».

Как устроен прогон

  1. воркер читает очередь адресов из опции;
  2. обходит их до 50 секунд;
  3. записывает обратно то, что не успел.

Если за эти 50 секунд сброс после выката поставил новый круг — полный перечень, главная первой, — воркер в конце прогона перезаписывает его своим старым остатком.

Симптом в журнале: счётчик «осталось» убывает со старого числа (857 → 851), а не с полного перечня (966).

Почему не помогло перечитать

Первая мысль — перед записью перечитать опцию и долить новое. Не работает: без постоянного кэша объектов (Redis, Memcached) WordPress держит прочитанную опцию в памяти до конца запроса. Повторный get_option возвращает тот же снимок, что и в начале прогона.

Лечение

function warm_queue_read(): array {
    wp_cache_delete('page_warm_queue', 'options');   // выбросить снимок
    return (array) get_option('page_warm_queue', []);
}

// в начале прогона
$cycle = get_option('page_warm_cycle_id');
$queue = warm_queue_read();

// ... обход ...

// в конце: если за время прогона начался новый круг — не затирать его
wp_cache_delete('page_warm_cycle_id', 'options');
if (get_option('page_warm_cycle_id') !== $cycle) {
    $fresh = warm_queue_read();
    $queue = array_values(array_unique(array_merge($fresh, $left)));
} else {
    $queue = $left;
}
update_option('page_warm_queue', $queue, false);
  • wp_cache_delete перед каждым чтением — получить значение из базы, а не снимок;
  • номер круга — сброс пишет новый номер (например, microtime), воркер сравнивает его со своим;
  • слияние вместо перезаписи — новый круг идёт первым, остаток старого — следом.

Как это проверить

Гонку трудно поймать вживую. Мы подменяли очередь в базе прямо во время прогона — на первом HTTP-запросе обходчика через фильтр pre_http_request — и смотрели, что окажется в опции после прогона.

После выката главная холодная, хотя прогрев идёт?

Пришлите адрес — проверю, не затирает ли обходчик новую очередь.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.