[WooCommerce] Action Scheduler 排程模組功能使用與最佳化筆記

本篇文章更新時間:2023/12/30
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣新台幣 贊助支持。


先前有筆記過 [WordPress] 詳解定時定期運作的服務: WP-Cron,而 Action Scheduler 其實就是一種進階版的 WP Cron 排程服務。

畢竟 WordPress 內建的功能實在有點太單薄,而 WooCommerce 這樣的電商服務又有大量排程的需求。各種需要排程檢查像是訂單付款狀態、商品庫存歸還等。

於是就發展出這一套服務,並且也獨立開源出來這個模組讓有需求的人可以使用。

官網其實各種說明(使用情境、方法等)都很清楚了,這邊就是筆記我實際的操作內容。

使用方法

  1. 一般來說,網站有安裝 WooCommerce 的話,就不用在自己的外掛或主題也安裝一份 Action Scheduler。
  2. 安裝使用 Action Scheduler 模組有兩個方法,一個是安裝他的外掛,另一個就是直接在客製化外掛或主題目錄下的程式碼引用
  3. 有安裝 WooCommerce 的情況下,要使用到 Action Scheduler 的方法只需要使用 $queue = WC()->queue(); 這方法呼叫就可以取得物件。
  4. 一個網站可能有多個外掛都使用自己的一套 Action Scheduler,但這模組有一個機制是會以「版本號最新」的為主來呼叫。所以對「版本」要有一點概念。
  5. 下面程式碼舉例「固定每小時去檢查有沒有未付款訂單,有的話就自動取消訂單」。
function mxp_auto_cancel_unpaid_order() {
    $args = array(
        'status'       => array('wc-pending'),
        'return'       => 'ids',
        'limit'        => 200,
        'date_created' => '<' . (time() - 3700), //一小時多 100 秒,確保沒問題
    );
    $orders = wc_get_orders($args);
    foreach ($orders as $index => $order_id) {
        $order = wc_get_order($order_id);
        if (!$order) {
            continue;
        }
        $order->update_status('cancelled');
        $order->add_order_note('超時未付款,系統自動取消訂單。');
        $order->save();
    }
}
// Step 1. 定義事件,並且加入一個 callback 方法
add_action('mxp_auto_cancel_unpaid_order_action', 'mxp_auto_cancel_unpaid_order');

function mxp_setting_cronjobs_action() {
    // Step 3. 在這個方法中,呼叫 Action Scheduler 來處理排程
    if (class_exists('WooCommerce')) {
        $queue = WC()->queue();
        if (!$queue->get_next('mxp_auto_cancel_unpaid_order_action')) {
            // 將「每小時檢查一次有沒有需要取消的訂單」方法加入排程
            $queue->schedule_recurring(gmdate('U'), HOUR_IN_SECONDS, 'mxp_auto_cancel_unpaid_order_action');
        }
    }
}
// Step 2. 在 wp 的事件中,註冊一個方法
add_action('wp', 'mxp_setting_cronjobs_action');

最佳化方法

使用這套工具也要知道它的原理。主要就是跟 WP Cron 差不多的觸發行為(有瀏覽量),其次就是會把排程任務透過「程式自己透過 HTTP 方式請求自己」來達成非同步多功的作業。

這樣的做法有缺點以及限制,像是:

  1. 如果一段時間沒人瀏覽網站會累積過多排程事件需要觸發,進入網站的瞬間會超級卡!
  2. 由於是透過 HTTP 方式請求回自己網站,所以請求的限制也會與主機本身伺服器的設定有關。
  3. 續前項,也會因為請求給自己造成伺服器的壓力倍增,連帶的整體網站運作變慢。
  4. 有些事件的註冊可能因為非同步的觸發導致重複註冊,操作這樣排程的邏輯要很小心,除了不好偵錯 Debug 外,運作過程有失敗也會難以察覺。
  5. 如果有大量的排程操作,會留下大量的操作記錄,預設紀錄是保留一個月,可以透過下面的方法來縮短以及增加請求上的限制。
// CRON 紀錄保留 14 天的設定
add_filter('action_scheduler_retention_period', function ($seconds) {
    return DAY_IN_SECONDS * 14;
}, 11, 1);

// 清除 取消的、錯誤的、完成的 CRON 紀錄
add_filter('action_scheduler_default_cleaner_statuses', function ($status) {
    return array(
        ActionScheduler_Store::STATUS_CANCELED,
        ActionScheduler_Store::STATUS_FAILED,
        ActionScheduler_Store::STATUS_COMPLETE,
    );
}, 11, 1);

// 每次清除紀錄的數量,預設 20 個,太慢惹!
add_filter('action_scheduler_cleanup_batch_size', function ($batch_size) {
    return 250;
}, 11, 1);

然後考慮安裝 Action Scheduler High Volume 或是以此外掛為基礎去調整適合自己環境的最佳請求形式參數,像是「批次處理量」、「請求時間限制」、「同時請求的數量」與「請求速率」等。

WooCommerce 的網站也是因為這樣的功能導致對主機的需求會比較高一些。但理解問題都是與 Cron 有關後,其實把「瀏覽量觸發」的機制改成「主機端主動定時執行」也會對效能有明顯的提升!

搭配 WP-CLI 方式,使用指令 wp cron event run --due-now 就可以定時跑排程解決一些佇列裡的任務,減輕網站負擔。

最後,因為 Webhook 的功能也預設使用 Action Scheduler 來處理,所以當網站收到 Webhook 請求後,並不會即時的做出反應,這可能會造成服務連動的困擾,要取消這個機制,可以加入下面的程式碼片段:

add_filter('woocommerce_webhook_deliver_async', '__return_false');

強迫當下接收到任務就去執行,缺點就是可能會卡一下,影響到回應時間,太久的話有機會發生 timeout 超時錯誤。


Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____36%_________]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


文章
Filter
Apply Filters
Mastodon