Когда в магазине на WooCommerce не создаются заказы, не отправляются письма или не продлеваются подписки — в 80% случаев причина кроется в Action Scheduler. Это асинхронная система очередей, встроенная в WooCommerce, которая обрабатывает фоновые задачи: создание заказов, отправку вебхуков, генерацию отчётов, продление подписок.
В отличие от стандартного wp-cron.php, который хранит задачи в опциях WordPress, Action Scheduler использует отдельные таблицы в базе данных и умеет обрабатывать десятки тысяч задач параллельно. Но при неправильной настройке или высокой нагрузке система начинает захлёбываться: задачи висят в статусе «in-progress» часами, а таблица actionscheduler_actions разрастается до миллионов записей.
Что такое Action Scheduler и как он работает
Action Scheduler (AS) — это библиотека для планирования и выполнения отложенных задач в WordPress. Её разработала команда Automattic (создатели WooCommerce), и сегодня она используется в десятках популярных плагинов:
- WooCommerce — обработка заказов, отправка email, обновление статистики
- WooCommerce Subscriptions — продление подписок, списание платежей
- WooCommerce Payments — обработка транзакций и рефандов
- Yoast SEO — генерация sitemap и индексация
- Rank Math — фоновая проверка ссылок и SEO-аудит
Архитектура Action Scheduler:
- Таблица actionscheduler_actions — хранит все задачи с их статусами (pending, in-progress, complete, failed, canceled)
- Таблица actionscheduler_groups — группирует задачи по плагинам
- Таблица actionscheduler_logs — логи выполнения задач
- Таблица actionscheduler_claims — блокировки для параллельной обработки
По умолчанию AS использует wp-cron.php для триггера обработки. Это создаёт две проблемы: задачи не выполняются на сайтах с низкой посещаемостью, а на нагруженных сайтах wp-cron не справляется с объёмом.
Шаг 1: Диагностика текущего состояния
Перед оптимизацией нужно понять, насколько плохо работает система. В админке WordPress перейдите в Инструменты → Запланированные действия (или WooCommerce → Статус → Запланированные действия).
Что проверять:
- Статус «In-Progress»: если таких задач больше 10-20 и они «висят» часами — система зависла
- Статус «Pending»: если в очереди тысячи задач, которые не обрабатываются — не хватает worker’ов
- Статус «Failed»: ошибки выполнения, требующие разбора
- Количество записей: если в таблице больше 100 000 записей — требуется очистка
Проверка через SQL-запросы:
Для точной диагностики подключаемся к базе данных и выполняем запросы:
-- Подсчёт задач по статусам
SELECT status, COUNT(*) as count
FROM wp_actionscheduler_actions
GROUP BY status;
-- Поиск "зависших" задач (in-progress больше 1 часа)
SELECT hook, COUNT(*) as count, MIN(claim_id) as claim_id
FROM wp_actionscheduler_actions
WHERE status = 'in-progress'
AND last_attempt_gmt < DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY hook;
-- Размер таблиц
SELECT
table_name AS 'Таблица',
ROUND(((data_length + index_length) / 1024 / 1024), 2) AS 'Размер (MB)',
table_rows AS 'Записей'
FROM information_schema.TABLES
WHERE table_schema = 'custom_code_db'
AND table_name LIKE 'wp_actionscheduler%';Шаг 2: Очистка старых записей
По умолчанию Action Scheduler хранит завершённые и отменённые задачи 30 дней. На крупных магазинах за месяц накапливаются сотни тысяч записей, что замедляет выборки.
Уменьшение периода хранения:
Добавляем в functions.php темы или в кастомный плагин:
// Хранить завершённые задачи только 7 дней (вместо 30)
add_filter( 'action_scheduler_retention_period', function() {
return 7 * DAY_IN_SECONDS;
} );
// Хранить отменённые задачи только 1 день
add_filter( 'action_scheduler_cancelled_retention_period', function() {
return 1 * DAY_IN_SECONDS;
} );Ручная очистка через WP-CLI:
Если таблица уже переполнена, встроенная очистка может не сработать из-за таймаутов. Используем WP-CLI для прямой очистки:
# Удаление всех завершённых задач старше 7 дней
wp action-scheduler clean --status=complete --before=7days
# Удаление всех отменённых задач
wp action-scheduler clean --status=cancelled
# Удаление всех failed-задач (если они накопились)
wp action-scheduler clean --status=failedОптимизация таблицы через SQL:
После массового удаления записей таблица остаётся раздутой. Оптимизируем её:
wp db query "OPTIMIZE TABLE wp_actionscheduler_actions"
wp db query "OPTIMIZE TABLE wp_actionscheduler_logs"Шаг 3: Увеличение производительности обработки
По умолчанию Action Scheduler обрабатывает по 20 задач за раз с интервалом в минуту. Для магазинов с большим количеством заказов этого недостаточно.
Увеличение размера батча:
// Обрабатывать по 100 задач за один запуск
add_filter( 'action_scheduler_queue_runner_batch_size', function() {
return 100;
} );
// Уменьшить интервал между запусками до 30 секунд
add_filter( 'action_scheduler_queue_runner_interval', function() {
return 30;
} );Настройка конкурентной обработки (concurrency):
Начиная с версии 3.0, Action Scheduler поддерживает параллельную обработку задач через систему claims:
// Разрешить до 5 одновременных worker'ов
add_filter( 'action_scheduler_queue_runner_concurrent_batches', function() {
return 5;
} );
// Увеличить время жизни claim до 10 минут
add_filter( 'action_scheduler_claim_ttl', function() {
return 10 * MINUTE_IN_SECONDS;
} );При увеличении concurrency критично иметь правильно настроенный пул процессов PHP-FPM, иначе сервер начнёт захлёбываться от нагрузки. Детальный расчёт pm.max_children приведён в руководстве по оптимизации PHP-FPM.
Шаг 4: Подключение системного cron
Самая важная настройка — отвязать Action Scheduler от wp-cron.php и запускать его через системный cron. Это гарантирует выполнение задач даже при отсутствии трафика и убирает нагрузку с фронтенда.
Отключение встроенного триггера:
// Отключаем стандартный триггер AS через wp-cron
add_filter( 'action_scheduler_run_queue', '__return_false' );Настройка системного cron:
Добавляем задачу в crontab для запуска каждые 1 минуту:
sudo crontab -u www-data -e
# Запуск обработки очереди каждую минуту
* * * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler run --batch-size=100 > /dev/null 2>&1
# Запуск очистки старых записей раз в день (в 4:00)
0 4 * * * cd /var/www/wordpress && /usr/local/bin/wp action-scheduler clean > /dev/null 2>&1Флаг --batch-size=100 должен совпадать со значением из фильтра action_scheduler_queue_runner_batch_size, чтобы параметры были консистентными.
Шаг 5: Решение проблемы "зависших" задач
Частая ситуация: задача переходит в статус "in-progress", но никогда не завершается. Это происходит при падении PHP-процесса (из-за нехватки памяти или таймаута) или при блокировке claim.
Автоматическое освобождение зависших задач:
// Считать задачу зависшей, если она выполняется больше 5 минут
add_filter( 'action_scheduler_timeout_period', function() {
return 5 * MINUTE_IN_SECONDS;
} );
// Уменьшить время до освобождения claim
add_filter( 'action_scheduler_failure_period', function() {
return 10 * MINUTE_IN_SECONDS;
} );Ручное освобождение через SQL:
Если в таблице много задач со статусом "in-progress", которые висят давно, освобождаем их вручную:
-- Возвращаем "зависшие" задачи в статус pending
UPDATE wp_actionscheduler_actions
SET status = 'pending', claim_id = 0
WHERE status = 'in-progress'
AND last_attempt_gmt < DATE_SUB(NOW(), INTERVAL 10 MINUTE);
-- Сбрасываем все claims (если их много)
UPDATE wp_actionscheduler_claims
SET date_created_gmt = NOW()
WHERE date_created_gmt < DATE_SUB(NOW(), INTERVAL 30 MINUTE);Шаг 6: Переход на HPOS (High-Performance Order Storage)
Начиная с WooCommerce 8.0, появилась функция HPOS, которая переносит хранение заказов из стандартной таблицы wp_posts в отдельную таблицу wp_wc_orders. Это напрямую влияет на производительность Action Scheduler.
Включение HPOS:
В админке: WooCommerce → Настройки → Продвинутые → Функции → включите "High-Performance Order Storage".
# Проверка статуса через WP-CLI
wp wc hpos status
# Синхронизация существующих заказов
wp wc hpos sync
# Окончательное включение
wp wc hpos enableHPOS снижает нагрузку на таблицы Action Scheduler в 3-5 раз, так как больше не нужно синхронизировать метаданные заказов через общие таблицы WordPress.
Шаг 7: Мониторинг через WP-CLI
Регулярный мониторинг состояния очереди предотвращает большинство проблем:
# Список всех запланированных задач с группировкой
wp action-scheduler list --status=pending --format=table
# Поиск задач конкретного хука
wp action-scheduler list --hook=woocommerce_process_product_file_download_paths
# Статистика по всем статусам
wp action-scheduler list --format=count
# Запуск одной задачи для отладки
wp action-scheduler run --hook=woocommerce_deliver_webhook_asyncСкрипт для ежедневной проверки:
#!/bin/bash
# /usr/local/bin/as-monitor.sh
PENDING=$(wp action-scheduler list --status=pending --format=count 2>/dev/null)
IN_PROGRESS=$(wp action-scheduler list --status=in-progress --format=count 2>/dev/null)
FAILED=$(wp action-scheduler list --status=failed --format=count 2>/dev/null)
# Отправка уведомления в Telegram при превышении порогов
if [ "$PENDING" -gt 1000 ] || [ "$IN_PROGRESS" -gt 50 ] || [ "$FAILED" -gt 10 ]; then
curl -s -X POST https://api.telegram.org/bot$BOT_TOKEN/sendMessage \
-d chat_id=$CHAT_ID \
-d text="⚠️ AS Alert: pending=$PENDING, in_progress=$IN_PROGRESS, failed=$FAILED"
fiДобавляем скрипт в cron для проверки каждые 15 минут. Интеграция с Telegram настраивается по аналогии с скриптом уведомлений о бэкапах.
Шаг 8: Использование кастомного кода с Action Scheduler
Action Scheduler — не только внутренняя система WooCommerce, но и мощный инструмент для собственных фоновых задач. Вместо создания своих cron-задач используйте AS для любых асинхронных операций.
Планирование одноразовой задачи:
// Запустить функцию через 1 час
as_schedule_single_action(
time() + HOUR_IN_SECONDS,
'customcode_send_notification',
array( 'user_id' => 123, 'message' => 'Hello!' ),
'customcode' // группа задач
);
// Обработчик
add_action( 'customcode_send_notification', function( $user_id, $message ) {
wp_mail( get_user_by( 'id', $user_id )->user_email, 'Уведомление', $message );
}, 10, 2 );Планирование повторяющейся задачи:
// Запускать каждый день в полночь
as_schedule_cron_action(
time(),
'0 0 * * *',
'customcode_daily_report',
array(),
'customcode'
);Обработка большого массива данных (batch):
function customcode_process_users_batch( $user_ids ) {
foreach ( $user_ids as $user_id ) {
as_enqueue_async_action(
'customcode_process_single_user',
array( $user_id ),
'customcode'
);
}
}
// Вызов для 10 000 пользователей
$all_users = get_users( array( 'fields' => 'ID' ) );
customcode_process_users_batch( $all_users );Такой подход автоматически использует всю инфраструктуру Action Scheduler: параллельную обработку, retry-механику, логирование и мониторинг.
Чек-лист оптимизации Action Scheduler
- ✅ Период хранения завершённых задач снижен до 7 дней
- ✅ Размер батча увеличен до 50-100
- ✅ Включена конкурентная обработка (3-5 worker'ов)
- ✅ Системный cron запускает
wp action-scheduler runкаждую минуту - ✅ Таблицы оптимизированы через
OPTIMIZE TABLE - ✅ Включён HPOS в WooCommerce
- ✅ Настроен мониторинг с уведомлениями в Telegram
Решение частых проблем
Таблица actionscheduler_actions не очищается
Стандартная очистка выполняется через wp-cron, который может не запускаться. Запускаем вручную: wp action-scheduler clean. Если таблица больше 10 ГБ, разделяем удаление на несколько запусков с параметром --before, чтобы избежать блокировок.
Задачи WooCommerce не выполняются после переноса сайта
При миграции через search-replace могут повредиться сериализованные данные в таблице задач. Выполняем: wp action-scheduler clean --status=failed и перезапускаем очередь. Если задачи продолжают падать — проверяем логи через wp action-scheduler list --hook=woocommerce.
Высокое потребление CPU при обработке очереди
Слишком большой batch-size или слишком много concurrent workers нагружают сервер. Снижаем до batch_size=25 и concurrency=2. Если нагрузка остаётся высокой — проверяем slow_query_log, как описано в руководстве по оптимизации MySQL, часто проблема в медленных SQL-запросах внутри задач.
Задачи дублируются и выполняются несколько раз
Это признак проблем с claim-системой. Проверяем, что не запущено несколько экземпляров обработчика одновременно (например, wp-cron + системный cron + плагин Action Scheduler). Оставляем только один триггер.
Итог
Action Scheduler — критически важный компонент современного WordPress, особенно для WooCommerce-магазинов. Правильная настройка системы очередей превращает её из источника проблем в надёжный инструмент для асинхронной обработки. Комбинация системного cron, оптимизированных батчей и HPOS даёт 5-10 кратный прирост производительности при обработке фоновых задач.