這篇文章也可以在我的博客中查看
定時任務
cron
Cron是Unix/Linux系統中的任務調度工具,允許用戶在預定的時間和日期間隔自動運行命令或腳本
它通過Cron表達式定義任務執行的頻率,該表達式包含分鐘、小時、日期等信息
我們可以利用Cron來定期執行維護、備份、數據處理等編程任務,無需手動干預
wp-cron
wp-cron是WordPress用于裝作cron的工具
這個打著cron名號的東西完全跟cron沒有關系,而且不可靠
為什么需要wp-cron
不不不,你不會想要它的
以下為官方的狡辯:
- WordPress核心和許多插件需要調度系統來執行基于時間的任務
然而,許多托管服務是共享的,并且不提供對系統調度程序的訪問 - 使用WordPress API設置定時任務,比在WordPress之外使用系統調度程序更簡單
- 使用系統調度程序時,如果時間流逝而任務未運行,將不會重新嘗試運行任務
而使用WP-Cron,所有預定的任務都被放入隊列中,并將在下一個機會(即下一次頁面加載)時運行
因此,雖然您無法百分之百確定您的任務將在何時運行,但可以百分之百確定它最終會運行。
是啊,cron可能是有缺點,但wp-cron絕對沒有任何優點
為什么不需要wp-cron
不是必須的
我的站點在不知情情況下,從來沒成功啟動過wp-cron
沒有它倒也沒出現任何問題😅
假調度
我們需要調度系統,但wp-cron根本不是調度系統
由于php腳本執行的特點,只有訪問時才會執行一遍腳本
因此WordPress是沒有守護進程的
所以你猜wp-cron怎么做到在任務時間到達時自己喚醒自己?
它做不到
它的執行邏輯是:
- 在頁面訪問時順便檢測是否有逾期任務
- 如有,fork一個后臺進程處理任務
這會出現什么問題?
- 如果網站訪問量很大:每次訪問都會加載執行wp-cron.php,這會增加服務器壓力
- 如果網站訪問量很少:沒有其它內置機制可以喚醒wp-cron.php,你的定時任務不會按時執行,直到有人訪問
這是非常嚴重的問題,它本身并不是一個可靠的調度系統
絕對不能依賴它執行時間敏感任務
抽象復制進程
等等?你剛剛說fork一個后臺進程?是怎么做的?
在WordPress中并不是通過克隆進程執行的,為了執行所有hook,它需要重新啟動一次php處理函數
所以wordpress的做法是……自己給自己發送一個http請求
不是開玩笑,這坨代碼切實出現在了WordPress的源碼中:
$cron_request = apply_filters('cron_request',array('url' => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),'key' => $doing_wp_cron,'args' => array('timeout' => 0.01,'blocking' => false,/** This filter is documented in wp-includes/class-wp-http-streams.php */'sslverify' => apply_filters( 'https_local_ssl_verify', false ),),),$doing_wp_cron
);$result = wp_remote_post( $cron_request['url'], $cron_request['args'] );
我不知道它為什么非得用這種做法,可能是WordPress只有按這種方式才能正常從頭啟動吧……
但這就是最致命的問題
昂貴的http請求
相當于DDoS攻擊自己!
首先http請求是非常昂貴的,你試試在for循環里面使用wp_remote_post
即使是訪問本機,你的頁面加載速度也會質的下降
雖然wp_cron只會發送1次
wp_remote_post
,但這做法還是太丑了
昂貴的互聯網請求
你以為它只會訪問環回地址嗎?錯啦!
域名解析請求
我們再來看看wp-cron
激活自己時訪問的地址:site_url('wp-cron.php')
理想情況下,它會:
- 根據站點site_url設置,域名解析
- 域名解析到本機IP地址
- 緩存解析結果,避免短期重復解析
- 識別為本機地址,走環回
OK這種情況雖然偶爾訪問了一次公網(域名解析),但還是可以接受的
但問題是,如果使用了CDN呢?
CDN請求
如果你使用了Cloudflare等CDN,代理你服務器的請求
那不好意思,每次請求都是一次完美的脫褲子放屁哦_:
- 根據站點site_url設置,域名解析
- 域名解析到CDN地址
- CDN轉發請求到你的服務器(本機)
- 最終交給WordPress,終于能夠開始執行wp-cron任務……
- 執行完任務,它還得返回結果……
- 結果又經過CDN,返回到了你的服務器……
我受不了了,這得多浪費資源啊,簡直是fork一下自己轟動全世界啊
洗
有沒有彌補的可能?能不能不訪問公網?
我很努力地試了,但我失敗了
稍微分享下吧
改host:在服務器中,將自己域名解析至127.0.0.1
理論上可行,但由于我服務器對Cloudflare開啟了客戶端SSL證書驗證
因此我的訪問被自己的服務器駁回了呢_
但我也不想不顧站點安全而關閉這個功能,所以,就此開擺吧……
或者有其他地址可以使wp_remote_post
直接訪問到本機的wp_cron.php
文件
但我放棄了 毀滅吧世界
關閉wp-cron
所以,告訴我,wp-cron到底有什么留存的價值?斃了它吧
打開config.php,在 That’s all, stop editing! Happy blogging.
之前加入:
define('DISABLE_WP_CRON', true);/* That’s all, stop editing! Happy blogging. */
把它送走