Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Фоновые задачи: 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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.