Фоновые задачи: Action Scheduler
Долгую работу — отправить заказ в учётную систему, обновить остатки, разослать письма — нельзя выполнять, пока покупатель ждёт страницу. Её откладывают в очередь. В WooCommerce встроена библиотека Action Scheduler: задача записывается в базу и выполняется позже отдельным запросом.
Как это работает
Задача — это имя хука и аргументы. Вы ставите её в очередь, а Action Scheduler в фоне вызывает do_action() с этим именем. Код задачи — обычная функция, подключённая к хуку.
Где писать код
Создайте файл includes/jobs.php и подключите его в acme-shop.php.
Задача «как можно скорее»
// wp-content/plugins/acme-shop/includes/jobs.php
add_action('woocommerce_order_status_processing', function (int $orderId) {
as_enqueue_async_action('acme_export_order', ['order_id' => $orderId], 'acme');
});
add_action('acme_export_order', function (int $orderId) {
$order = wc_get_order($orderId);
if (!$order || $order->get_meta('_acme_exported') === 'yes') {
return;
}
$response = wp_remote_post('https://erp.example.com/orders', [
'headers' => ['Content-Type' => 'application/json'],
'body' => wp_json_encode(['id' => $orderId, 'total' => $order->get_total()]),
]);
if (is_wp_error($response)) {
throw new Exception($response->get_error_message());
}
$order->update_meta_data('_acme_exported', 'yes');
$order->save();
});Первая функция срабатывает при оплате заказа и только ставит задачу — это мгновенно. Вторая выполняется в фоне и отправляет заказ. Аргументы из массива передаются функции по порядку. Третий аргумент acme — группа, по ней задачи плагина легко найти.
Функции
| Функция | Что делает |
|---|---|
as_enqueue_async_action($hook, $args, $group) | Выполнить как можно скорее |
as_schedule_single_action($time, $hook, $args, $group) | Выполнить один раз в указанное время |
as_schedule_recurring_action($time, $interval, $hook, $args, $group) | Повторять с интервалом в секундах |
as_has_scheduled_action($hook, $args, $group) | Есть ли такая задача в очереди |
as_unschedule_all_actions($hook, $args, $group) | Отменить задачи |
Отложенная задача
// wp-content/plugins/acme-shop/includes/jobs.php
add_action('woocommerce_order_status_completed', function (int $orderId) {
as_schedule_single_action(time() + 7 * DAY_IN_SECONDS, 'acme_ask_review', ['order_id' => $orderId], 'acme');
});
add_action('acme_ask_review', function (int $orderId) {
$order = wc_get_order($orderId);
if ($order) {
wp_mail($order->get_billing_email(), 'Как вам покупка?', 'Оставьте отзыв о товаре на сайте.');
}
});Через неделю после выполнения заказа покупатель получит письмо с просьбой об отзыве.
Повторяющаяся задача
// wp-content/plugins/acme-shop/includes/jobs.php
add_action('init', function () {
if (!as_has_scheduled_action('acme_sync_stock', [], 'acme')) {
as_schedule_recurring_action(time(), HOUR_IN_SECONDS, 'acme_sync_stock', [], 'acme');
}
});
add_action('acme_sync_stock', function () {
// запрос остатков во внешней системе и обновление товаров
});Проверка as_has_scheduled_action() не даёт создавать новую задачу при каждой загрузке страницы. Синхронизация будет запускаться раз в час.
Очередь в панели
Откройте «WooCommerce → Статус → Запланированные действия». В списке видны задачи со статусами «Ожидает», «Выполнено», «Не удалось», а в поиске можно набрать acme_export_order. Задачу в ожидании запускают вручную ссылкой «Выполнить» под её названием. Если функция выбросила исключение, задача попадает в «Не удалось», а текст ошибки виден в столбце журнала.
Запуск из консоли
По умолчанию очередь обрабатывается, пока на сайт кто-то заходит. На рабочем сервере её запускают системным планировщиком:
wp action-scheduler run --group=acmeКоманда выполняет все готовые задачи группы и печатает их число.
Частая ошибка
Задача не рассчитана на повторный запуск. Сеть оборвалась после отправки, задачу запустили вручную ещё раз — и заказ ушёл в учётную систему дважды. Перед действием проверяйте, не сделано ли оно уже: в примере для этого служит отметка _acme_exported.