本篇文章更新時間:2023/12/30
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣 或 新台幣 贊助支持。
先前有筆記過 [WordPress] 詳解定時定期運作的服務: WP-Cron,而 Action Scheduler 其實就是一種進階版的 WP Cron 排程服務。
畢竟 WordPress 內建的功能實在有點太單薄,而 WooCommerce 這樣的電商服務又有大量排程的需求。各種需要排程檢查像是訂單付款狀態、商品庫存歸還等。
於是就發展出這一套服務,並且也獨立開源出來這個模組讓有需求的人可以使用。
官網其實各種說明(使用情境、方法等)都很清楚了,這邊就是筆記我實際的操作內容。
使用方法
- 一般來說,網站有安裝 WooCommerce 的話,就不用在自己的外掛或主題也安裝一份 Action Scheduler。
- 安裝使用 Action Scheduler 模組有兩個方法,一個是安裝他的外掛,另一個就是直接在客製化外掛或主題目錄下的程式碼引用。
- 有安裝 WooCommerce 的情況下,要使用到 Action Scheduler 的方法只需要使用
$queue = WC()->queue();
這方法呼叫就可以取得物件。 - 一個網站可能有多個外掛都使用自己的一套 Action Scheduler,但這模組有一個機制是會以「版本號最新」的為主來呼叫。所以對「版本」要有一點概念。
- 下面程式碼舉例「固定每小時去檢查有沒有未付款訂單,有的話就自動取消訂單」。
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 方式請求自己」來達成非同步多功的作業。
這樣的做法有缺點以及限制,像是:
- 如果一段時間沒人瀏覽網站會累積過多排程事件需要觸發,進入網站的瞬間會超級卡!
- 由於是透過 HTTP 方式請求回自己網站,所以請求的限制也會與主機本身伺服器的設定有關。
- 續前項,也會因為請求給自己造成伺服器的壓力倍增,連帶的整體網站運作變慢。
- 有些事件的註冊可能因為非同步的觸發導致重複註冊,操作這樣排程的邏輯要很小心,除了不好偵錯 Debug 外,運作過程有失敗也會難以察覺。
- 如果有大量的排程操作,會留下大量的操作記錄,預設紀錄是保留一個月,可以透過下面的方法來縮短以及增加請求上的限制。
// 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 超時錯誤。