Action Scheduler в WooCommerce: Исправляем зависшие задачи и оптимизируем очереди

Звонит клиент. Говорит: «Покупатель оформил заказ три часа назад, а письмо с подтверждением так и не пришло». Открываете WooCommerce — заказ есть, статус «В обработке», всё вроде нормально. Но письмо не ушло. И вебхук в CRM не сработал. И подписка не продлилась.

Знакомо? Тогда добро пожаловать в мир Action Scheduler — тихой рабочей лошадки WooCommerce, о которой никто не вспоминает, пока она не сломается.

Action Scheduler — это система очередей задач в WooCommerce. Она обрабатывает всё, что должно выполняться в фоне: отправка писем, обработка вебхуков, продление подписок, обновление остатков, генерация отчётов. Когда она работает — вы её не замечаете. Когда перестаёт — магазин начинает разваливаться на части.

За годы работы я отладил Action Scheduler на десятках магазинов. И честно? Большинство проблем сводятся к пяти вещам. Давайте пройдёмся по каждой.

Что такое Action Scheduler и как он работает

Представьте Action Scheduler как список дел для вашего магазина. Когда что-то должно произойти в фоне — отправить письмо, обработать вебхук, продлить подписку — WooCommerce не делает это сразу. Он добавляет задачу в очередь и говорит: «Эй, Action Scheduler, разберись с этим, когда будет минутка».

Эти задачи хранятся в отдельных таблицах базы данных:

  • wp_actionscheduler_actions — сама очередь (что нужно сделать)
  • wp_actionscheduler_logs — история выполненных задач
  • wp_actionscheduler_groups — группировка задач (используется редко)

По умолчанию Action Scheduler проверяет очередь каждую минуту и выполняет задачи, которые должны были запуститься. Просто, да? Не совсем.

Потому что «каждую минуту» зависит от WordPress cron. А если вы не настроили системный cron, ваш cron работает только когда кто-то заходит на сайт. Нет посетителей — нет cron — нет выполненных задач.

Это проблема номер один. Но мы к ней вернёмся.

Как проверить, работает ли Action Scheduler

Прежде чем что-то чинить, давайте посмотрим, что вообще происходит. Идём в WooCommerce → Статус → Запланированные действия (или Инструменты → Запланированные действия в новых версиях).

Увидите список задач со статусами:

  • Pending (Ожидание): ждут выполнения
  • In-progress (В процессе): выполняются прямо сейчас
  • Complete (Выполнено): сделаны
  • Failed (Ошибка): что-то пошло не так
  • Canceled (Отменено): отменены вручную

На что обратить внимание:

Красный флаг №1: Сотни задач в статусе «Ожидание»

Если видите 500+ ожидающих задач — очередь забилась. Action Scheduler не успевает обрабатывать. Обычно это значит, что cron работает недостаточно часто или задачи слишком тяжёлые.

Красный флаг №2: Задачи застряли в «В процессе»

Если видите задачи, которые висят в «in-progress» часами (или днями) — они зависли. Что-то сломалось во время выполнения, и Action Scheduler не знает, что с ними делать. Починим ниже.

Красный флаг №3: Много «Failed» задач

Ошибки означают, что что-то сломано. Кликните на задачу, посмотрите сообщение об ошибке. Частые причины: нехватка памяти, таймауты, конфликты с другими плагинами.

Красный флаг №4: Старые выполненные задачи копятся

По умолчанию Action Scheduler хранит логи вечно. Если у вас 100 000+ выполненных задач — база раздута. Почистим.

Фикс №1: Зависшие задачи (самая частая проблема)

Видите задачи, застрявшие в «in-progress» часами? Может, даже днями? Это случается, когда задача падает во время выполнения — PHP не хватает памяти, скрипт превышает таймаут, сервер перезагружается.

Action Scheduler помечает задачу как «in-progress» и ждёт завершения. Но она никогда не завершается. Так и висит.

Правильное решение (восстановление через SQL)

В WP-CLI нет встроенной команды для возврата таких задач в очередь без удаления. Самый надёжный способ — прямой запрос к базе данных, который сбрасывает статус и снимает блокировку (claim_id).

-- Сбрасываем зависшие задачи (старше 5 минут) обратно в pending
UPDATE wp_actionscheduler_actions 
SET status = 'pending', claim_id = 0
WHERE status = 'in-progress' 
AND last_attempt_gmt < DATE_SUB(NOW(), INTERVAL 5 MINUTE);

Обязательно обнуляйте claim_id, иначе диспетчер задач не подхватит их снова.

Ручной способ через админку (использовать осторожно)

Идём в WooCommerce → Статус → Запланированные действия. Фильтруем по «In-progress». Выделяем все. Жмём «Отменить». Важно: отмена безвозвратно удаляет эти задачи. Если они были созданы разово (например, письмо о заказе), они не появятся снова. Применяйте этот метод только если уверены, что задача может быть безопасно удалена или будет пересоздана плагином.

Лучше используйте SQL — он перезапускает задачу, а не уничтожает её.

Как предотвратить в будущем:

  • Увеличьте memory_limit PHP минимум до 512 МБ (разбирали в статье про memory_limit)
  • Увеличьте max_execution_time до 300 секунд
  • Проверьте конфликты плагинов (отключайте по одному и смотрите, исчезают ли зависшие задачи)
  • Используйте системный cron вместо WP-Cron для более надёжного выполнения

Фикс №2: Проблемы с cron (тихий убийца)

Помните, что я говорил раньше? Action Scheduler зависит от WordPress cron. А WordPress cron работает только когда кто-то заходит на сайт.

Если у вашего магазина низкий трафик ночью (скажем, с 2 до 6 утра), Action Scheduler не будет работать часами. Письма копятся. Вебхуки падают. Подписки не продлеваются.

Именно поэтому системный cron обязателен для любого серьёзного магазина на WooCommerce.

Настраиваем системный cron для Action Scheduler:

# Открываем crontab
crontab -e

# Запуск всех ожидающих задач каждую минуту
* * * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler run >> /var/log/action-scheduler.log 2>&1

Теперь Action Scheduler работает каждую минуту, независимо от трафика. Никаких зависших писем. Никаких пропущенных вебхуков.

Как проверить, что cron реально отрабатывает:

Выполните запрос, который покажет время последней выполненной задачи:

wp db query "SELECT MAX(scheduled_date_gmt) FROM wp_actionscheduler_actions WHERE status='complete';"
# Если время отстаёт больше чем на пару минут — cron не работает.

Или просто откройте страницу «Запланированные действия» в админке и убедитесь, что вкладка «Pending» не растёт бесконечно.

Фикс №3: Оптимизация базы данных (чистим завалы)

Action Scheduler хранит логи вечно. Через год у вас могут быть миллионы строк в wp_actionscheduler_logs. Это раздувает базу и замедляет запросы.

Чистим старые выполненные задачи:

# Удаляем выполненные задачи старше 30 дней
wp action-scheduler clean --status=complete --older-than=30 days

# Удаляем ошибки старше 7 дней
wp action-scheduler clean --status=failed --older-than=7 days

# Удаляем отменённые старше 7 дней
wp action-scheduler clean --status=canceled --older-than=7 days

Автоматизируем очистку через cron:

# Добавляем в crontab (запуск каждый день в 3 часа ночи)
0 3 * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler clean --status=complete --older-than=30 days > /dev/null 2>&1
0 3 * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler clean --status=failed --older-than=7 days > /dev/null 2>&1

Оптимизируем таблицы:

# После очистки оптимизируем таблицы
wp db optimize wp_actionscheduler_actions
wp db optimize wp_actionscheduler_logs

На магазине с 500 000+ задач это может уменьшить размер базы на 2-3 ГБ и ускорить запросы в 10-20 раз.

Фикс №4: Проблемы с памятью и таймаутами

Если видите много «Failed» задач с ошибками вроде «Allowed memory size exhausted» или «Maximum execution time exceeded» — нужно увеличить лимиты PHP.

Увеличиваем лимит памяти:

// В wp-config.php
define( 'WP_MEMORY_LIMIT', '512M' );
define( 'WP_MAX_MEMORY_LIMIT', '1G' ); // Для админки и cron

Увеличиваем время выполнения:

; В .user.ini или php.ini
max_execution_time = 300
max_input_time = 300

Специально для WP-CLI:

# Создаём wp-cli.yml в корне WordPress
php:
  memory_limit: 1G
  max_execution_time: 300

Теперь WP-CLI будет использовать эти лимиты при выполнении задач Action Scheduler.

Фикс №5: Масштабирование для высоконагруженных магазинов

Если вы обрабатываете 10 000+ задач в день (типично для магазинов с подписками, вебхуками или высоким объёмом заказов), стандартная настройка Action Scheduler не потянет. Нужно оптимизировать.

Увеличиваем размер батча:

По умолчанию Action Scheduler обрабатывает 20 задач за батч. Для высоконагруженных магазинов увеличиваем:

// В functions.php
add_filter( 'action_scheduler_queue_runner_batch_size', function( $batch_size ) {
    return 100; // Обрабатываем 100 задач за батч
} );

add_filter( 'action_scheduler_queue_runner_consecutive_batches_count', function( $count ) {
    return 5; // Запускаем 5 батчей за один прогон cron
} );

Теперь Action Scheduler будет обрабатывать 500 задач за прогон cron (100 × 5) вместо 20.

Используем асинхронную обработку:

Для очень высоконагруженных магазинов можно вынести Action Scheduler в отдельный процесс через WP Background Processing или Cavalcade (от Human Made). Это продвинутый уровень, но он позволяет запускать Action Scheduler на отдельном сервере вообще.

Мониторим глубину очереди:

# Проверяем количество ожидающих задач
wp db query "SELECT status, COUNT(*) as count FROM wp_actionscheduler_actions GROUP BY status;"

Если ожидающих задач стабильно больше 1000 — нужно либо увеличить размер батча, либо запускать cron чаще, либо оптимизировать сами задачи.

Мониторинг Action Scheduler (чтобы не было сюрпризов)

Нельзя починить то, за чем не следишь. Вот простой скрипт для проверки здоровья Action Scheduler и алертов, если что-то не так.

Создаём скрипт мониторинга:

#!/bin/bash
# /usr/local/bin/action-scheduler-monitor.sh

# Задайте свои BOT_TOKEN и CHAT_ID
BOT_TOKEN="123456:ABC-DEF..."
CHAT_ID="-123456789"

cd /var/www/wordpress

PENDING=$(wp db query "SELECT COUNT(*) FROM wp_actionscheduler_actions WHERE status = 'pending';" --skip-column-names)
STUCK=$(wp db query "SELECT COUNT(*) FROM wp_actionscheduler_actions WHERE status = 'in-progress' AND last_attempt_gmt < DATE_SUB(NOW(), INTERVAL 10 MINUTE);" --skip-column-names)
FAILED=$(wp db query "SELECT COUNT(*) FROM wp_actionscheduler_actions WHERE status = 'failed' AND last_attempt_gmt > DATE_SUB(NOW(), INTERVAL 1 HOUR);" --skip-column-names)

if [ "$PENDING" -gt 500 ] || [ "$STUCK" -gt 10 ] || [ "$FAILED" -gt 50 ]; then
    curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
        -d chat_id="$CHAT_ID" \
        -d text="⚠️ Action Scheduler Alert:
Pending: $PENDING
Stuck: $STUCK
Failed (last hour): $FAILED"
fi

Добавляем в cron (каждые 15 минут):

*/15 * * * * /usr/local/bin/action-scheduler-monitor.sh

Теперь вы будете получать сообщение в Telegram, если Action Scheduler начнёт отставать. Никаких удивлённых клиентов.

Частые хуки Action Scheduler (и что они делают)

Не все задачи одинаковы. Вот самые распространённые хуки, которые вы увидите в очереди:

Хук Что делает Приоритет
woocommerce_deliver_webhook_async Отправляет вебхуки в сторонние сервисы Критичный
woocommerce_single_transactional_email Отправляет письма о заказах, доставке и т.д. Критичный
woocommerce_scheduled_subscription_payment Обрабатывает продление подписок Критичный
woocommerce_cleanup_sessions Чистит устаревшие сессии покупателей Низкий
woocommerce_cleanup_personal_data Удаляет старые персональные данные (GDPR) Низкий
woocommerce_update_product_count Обновляет счётчики товаров Средний

Если видите критичные хуки (вебхуки, письма, подписки) зависшими или с ошибками — бросайте всё и чините. Они напрямую влияют на опыт клиентов и выручку.

Частые вопросы

Почему WooCommerce не отправляет письма?

В 90% случаев — это Action Scheduler. Проверяйте WooCommerce → Статус → Запланированные действия и ищите ожидающие или зависшие woocommerce_single_transactional_email. Если видите их — cron не работает. Настраивайте системный cron (см. Фикс №2).

Как часто должен работать Action Scheduler?

Для большинства магазинов — каждую минуту нормально. Для высоконагруженных (10 000+ задач в день) может понадобиться запуск каждые 30 секунд или увеличение размера батча. Но не опускайтесь ниже 1 минуты без конкретной причины — это просто добавляет накладные расходы.

Можно ли удалить таблицы Action Scheduler?

Нет. Action Scheduler — это ядро WooCommerce. Если удалите таблицы, вебхуки, письма и подписки перестанут работать. Можно почистить старые данные (см. Фикс №3), но не удаляйте таблицы целиком.

Почему так много задач woocommerce_cleanup_sessions?

Это нормально. WooCommerce планирует очистку сессий каждый час. Если у вас высокий трафик, увидите много таких задач. Они низкого приоритета и могут безопасно игнорироваться (или чиститься через Фикс №3).

Как временно приостановить Action Scheduler?

Можно отключить queue runner:

// В functions.php
add_filter( 'action_scheduler_queue_runner_enabled', '__return_false' );

Но осторожно — это останавливает все фоновые задачи. Делайте это только если точно знаете, что делаете.

Action Scheduler занимает слишком много места в базе. Что делать?

Запустите команды очистки из Фикса №3. Если всё равно слишком большая — уменьшите период хранения (удаляйте выполненные задачи через 7 дней вместо 30). Или вынесите на отдельный сервер базы данных, если у вас высоконагруженный магазин.

Чек-лист: здоров ли ваш Action Scheduler?

  • ✅ Настроен системный cron (не зависит от WP-Cron)
  • ✅ Нет зависших задач (in-progress больше 10 минут)
  • ✅ Ожидающих задач меньше 500
  • ✅ Ошибок меньше 50 в час
  • ✅ Выполненные задачи чистятся ежемесячно
  • ✅ Лимит памяти PHP минимум 512 МБ
  • max_execution_time минимум 300 секунд
  • ✅ Настроен скрипт мониторинга (алерты в Telegram)
  • ✅ Критичные хуки (вебхуки, письма, подписки) выполняются вовремя
  • ✅ Таблицы базы оптимизированы (запускайте OPTIMIZE TABLE ежемесячно)

Итог

Action Scheduler — одна из тех вещей, о которых никто не думает, пока она не сломается. А когда ломается — ломается серьёзно. Письма перестают приходить. Вебхуки падают. Подписки не продлеваются. Клиенты злятся.

Но починка straightforward. Настройте системный cron. Почистите старые задачи. Увеличьте лимиты памяти. Мониторьте очередь. Сделайте эти пять вещей — и больше никогда не столкнётесь с проблемами Action Scheduler.

Лучшая часть? На реализацию уходит меньше часа. А сэкономит часы отладки в будущем.

Так что откройте терминал. Выполните SQL-запрос для проверки последней выполненной задачи. Проверьте очередь. И убедитесь, что всё работает гладко. Ваши клиенты скажут спасибо.

Ну или хотя бы не будут писать вам в 2 часа ночи с вопросом, где подтверждение их заказа.