วิธีปิด WP-Cron และตั้งค่า System Cron ด้วย WP-CLI
WP-Cron ทำงานเฉพาะเมื่อมีผู้เข้าชมทำให้เว็บไซต์โหลดช้าหรือค้าง เรียนรู้วิธีปิดการทำงานและย้ายไปใช้ System Cron ผ่าน WP-CLI เพื่อความแม่นยำ พร้อมวิธีตรวจสอบสถานะการทำงานจริง
wp-cron คืออะไร และเหตุใดจึงควรใช้ system cron แทน
WP-Cron คือตัวจัดตารางเวลาทำงานที่ฝังอยู่ใน WordPress ซึ่งจะทำงานก็ต่อเมื่อมีผู้เข้าชมหน้าเว็บไซต์เท่านั้น ไม่มีกระบวนการใดภายใน WordPress ที่จะเริ่มทำงานได้ด้วยตัวเอง ในทุกคำขอที่ไม่ได้รับข้อมูลจากแคช WordPress จะอ่านรายการงานที่กำหนดไว้ หากมีงานใดถึงกำหนด ระบบจะส่ง HTTP request อีกชุดหนึ่งกลับไปยังตัวเองที่ /wp-cron.php เพื่อประมวลผลงานนั้น การย้ายงานดังกล่าวไปไว้ใน system cron จะช่วยให้งานทำงานตามกำหนดเวลาที่แน่นอนและคาดการณ์ได้ ไม่ว่าในขณะนั้นจะมีผู้เข้าชมเว็บไซต์เป็นพันคนหรือไม่มีเลยก็ตาม
มีเพียงสองส่วนที่ทำหน้าที่หลัก ได้แก่ ค่าคงที่ใน wp-config.php และรายการใน crontab ส่วนที่เหลือในคู่มือนี้คือรายละเอียดที่สองส่วนนั้นไม่ได้ระบุไว้ เช่น การกำหนดว่างานต้องรันด้วยสิทธิ์ของผู้ใช้ใด วิธีตรวจสอบว่าเหตุการณ์ที่กำหนดไว้ได้ทำงานจริงหรือไม่ และสาเหตุ 3 ประการที่ทำให้การตั้งค่าล้มเหลวโดยไม่แสดงข้อความแจ้งเตือนใดๆ บนหน้าเว็บไซต์
ตัวอย่างในคู่มือนี้ใช้ /srv/www/example.com เป็นไดเรกทอรีของ WordPress และ www-data เป็นผู้ใช้ของเว็บเซิร์ฟเวอร์ โปรดแทนที่ด้วยพาธและชื่อผู้ใช้ของคุณเองในทุกจุดที่เกี่ยวข้อง
ผู้เข้าชมรายใดเป็นผู้กระตุ้นค่าใช้จ่าย cron บนเว็บไซต์ที่มีการใช้งานสูง
ทุกคำขอที่ไม่ได้ถูกแคชจะต้องเสียค่าใช้จ่ายในการตรวจสอบ WordPress จะโหลดออปชัน cron เปรียบเทียบการประทับเวลา และเมื่อถึงกำหนดเวลา ระบบจะเรียก spawn_cron() ซึ่งจะส่งคำขอ loopback แบบไม่บล็อกไปยัง /wp-cron.php ผู้เข้าชมไม่ต้องรอผลลัพธ์ แต่ PHP worker จะต้องรอ บน VPS ขนาดเล็กที่รัน PHP-FPM ด้วย pm.max_children = 5 งานตามกำหนดการที่ทำงานช้าเพียงงานเดียวอาจยึดครองความสามารถในการประมวลผล PHP ของคุณไปถึงหนึ่งในห้าเป็นเวลานาน และมีโอกาสสูงที่จะถูกกระตุ้นในช่วงเวลาที่มีผู้เข้าชมหนาแน่นที่สุดของคุณ เนื่องจากเป็นช่วงเวลาที่มีการโหลดหน้าเว็บมากที่สุด
WordPress มีการจำกัดการทำงานซ้ำซ้อน โดยจะทำการล็อกซึ่งมีอายุการใช้งานเท่ากับ WP_CRON_LOCK_TIMEOUT หรือ 60 วินาทีโดยค่าเริ่มต้น เพื่อไม่ให้ผู้เข้าชมที่เข้ามาพร้อมกันเริ่มการทำงานพร้อมกันหลายครั้ง การล็อกนี้ช่วยจำกัดการทำงานซ้ำซ้อน แต่ไม่ได้ย้ายภาระงานออกไปจากเส้นทางการประมวลผลคำขอหลัก
จงนับจำนวนครั้งที่ cron ทำงานบนเซิร์ฟเวอร์ของคุณเองก่อนที่จะตัดสินว่ามันเป็นปัญหาหรือไม่ คำขอ loopback แต่ละรายการจะปรากฏใน access log ของเว็บเซิร์ฟเวอร์:
sudo grep -c 'wp-cron.php' /var/log/nginx/access.logApache จะเขียนลงใน /var/log/apache2/access.log แทน หากจำนวนครั้งสูงถึงหลักพันต่อวัน นั่นถือเป็นต้นทุนที่แท้จริง และเป็นตัวเลขที่คุณควรวัดผลบนเครื่องของคุณเองแทนที่จะอ่านจากบทความ เช่นเดียวกับที่คุณจะ ทำ benchmark VPS ก่อนและหลังการเปลี่ยนแปลงอื่นใด
การทำแคชจะเปลี่ยนสถานการณ์ไป หาก page cache สามารถตอบสนองคำขอส่วนใหญ่ด้วยไฟล์ HTML แบบคงที่ PHP จะไม่ทำงานสำหรับคำขอเหล่านั้น ดังนั้นการตรวจสอบ cron จึงไม่เกิดขึ้น เว็บไซต์ที่มีการใช้งานสูงและมีการทำแคชอย่างหนักจะเริ่มมีพฤติกรรมเหมือนกับเว็บไซต์ที่มีการใช้งานน้อยตามที่อธิบายไว้ด้านล่าง
เมื่อผู้เข้าชมเป็นตัวกระตุ้นให้ cron ทำงานบนเว็บไซต์ที่มีทราฟฟิกน้อย
หากไม่มีผู้เข้าชม cron ก็จะไม่ทำงาน เว็บไซต์ที่มีผู้เข้าชมเพียงไม่กี่ครั้งต่อวันจะรันงานตามกำหนดการตามจำนวนครั้งที่มีผู้เข้าชมเข้ามา โดยจะเกิดขึ้นในช่วงเวลาสุ่มตามจังหวะที่ผู้เข้าชมเหล่านั้นเข้ามายังเว็บไซต์
อาการที่เกิดขึ้นจะมีลักษณะเดียวกันทั้งหมด โพสต์ที่ตั้งเวลาไว้ตอน 09:00 จะยังคงอยู่ในรายการโพสต์โดยมีสถานะเป็น Missed schedule จนกว่าจะมีคนโหลดหน้าเว็บ ปลั๊กอินสำรองข้อมูลจะข้ามการทำงานในช่วงกลางคืน การตรวจสอบการอัปเดตจะล่าช้า ทำให้แดชบอร์ดไม่แสดงรายการอัปเดตแม้ว่าจะมีรุ่นความปลอดภัยออกมาแล้วก็ตาม อีเมลคำสั่งซื้อ ประกาศการต่ออายุ และคำเตือนการหมดอายุจะถูกส่งออกไปล่าช้า
เหตุการณ์เหล่านี้ไม่ปรากฏใน log ว่าเป็นข้อผิดพลาด งานดังกล่าวไม่ได้ถือว่าล่าช้าในมุมมองของ WordPress เนื่องจากงานนั้นยังไม่เคยถูกเริ่มทำงานเลย
ขั้นตอนที่ 1: ปิดการทำงานของ visitor trigger ใน wp-config.php
เปิดไฟล์ /srv/www/example.com/wp-config.php แล้วเพิ่มค่าคงที่ดังนี้:
define( 'DISABLE_WP_CRON', true );ให้วางไว้ เหนือ บรรทัดที่มีข้อความ /* That's all, stop editing! Happy publishing. */ เนื่องจากบรรทัดที่อยู่ถัดจากคอมเมนต์นั้นจำเป็นต้องใช้ wp-settings.php และ wp-settings.php คือจุดที่ WordPress เชื่อมต่อการตรวจสอบ cron เข้ากับ init หากกำหนดค่าคงที่หลังจากคำสั่ง require นั้น ค่าที่ตั้งไว้จะสายเกินไปที่จะส่งผลใดๆ ทำให้ไฟล์ดูเหมือนถูกต้องแต่ตัว trigger ยังคงทำงานอยู่
ตรวจสอบให้แน่ใจว่าบรรทัดดังกล่าวอยู่ในตำแหน่งที่คุณต้องการ:
grep -n "DISABLE_WP_CRON\|stop editing" /srv/www/example.com/wp-config.phpค่าคงที่นี้ไม่ได้หยุดการตั้งเวลาของเหตุการณ์ต่างๆ ปลั๊กอินจะยังคงเพิ่มงานเข้าสู่คิวตามปกติเหมือนเดิม แต่จะหยุดการโหลดหน้าเว็บไม่ให้เรียกใช้งานคิวดังกล่าว ซึ่งหมายความว่าคิวจะไม่ถูกประมวลผลจนกว่าคุณจะทำขั้นตอนที่ 3 เสร็จสิ้น
นอกจากนี้ ค่าคงที่นี้ไม่ได้บล็อกการร้องขอโดยตรงไปยัง /wp-cron.php ใครก็ตามยังสามารถเรียก URL นั้นได้ ซึ่งโดยปกติแล้วไม่มีอันตรายเนื่องจากไฟล์จะรันเฉพาะงานที่ถึงกำหนดเท่านั้น การบล็อกไฟล์ดังกล่าวในไฟล์ตั้งค่าของเว็บเซิร์ฟเวอร์เป็นทางเลือกเสริม หากคุณเลือกบล็อกไฟล์นี้ ระบบสำรอง curl ที่ระบุไว้ในช่วงท้ายของคู่มือนี้จะไม่สามารถทำงานได้เช่นกัน
ขั้นตอนที่ 2: ติดตั้ง WP-CLI
WP-CLI เป็นเครื่องมือบรรทัดคำสั่งอย่างเป็นทางการสำหรับ WordPress ซึ่งจำเป็นต้องใช้ PHP command line binary ซึ่งเป็นแพ็กเกจแยกต่างหากจาก PHP module ของเว็บเซิร์ฟเวอร์
php -v
sudo apt install -y php-cliติดตั้ง WP-CLI จากไฟล์ phar build ตามที่คู่มือการติดตั้งอย่างเป็นทางการแนะนำ:
cd /tmp
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
wp --infophp wp-cli.phar --info จะแสดงพาธของ PHP binary, เวอร์ชันของ PHP และเวอร์ชันของ WP-CLI หากแสดงข้อมูลครบทั้งสามรายการ แสดงว่าไฟล์ phar ทำงานได้ปกติ ณ เดือนสิงหาคม 2026 คู่มือการติดตั้งระบุว่า PHP 7.2.24 คือเวอร์ชันขั้นต่ำที่รองรับ และเนื่องจาก Ubuntu 24.04 มาพร้อมกับ PHP 8.3 เซิร์ฟเวอร์ปัจจุบันจึงผ่านเกณฑ์นี้อย่างไม่มีปัญหา คุณสามารถอัปเดตในภายหลังได้ด้วย sudo wp cli update
ให้รัน WP-CLI ในฐานะผู้ใช้ของเว็บไซต์เท่านั้น ห้ามรันในฐานะ root:
sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com core versionหากรันในฐานะ root ตัว WP-CLI จะปฏิเสธการทำงาน:
Error: YIKES! It looks like you're running this as root.ระบบจะแนะนำให้ใช้ --allow-root แต่ห้ามใช้คำสั่งดังกล่าวในที่นี้ เนื่องจากเหตุผลจะอธิบายอยู่ในโหมดความล้มเหลวแรกด้านล่าง
นอกจากนี้ โปรดทราบว่า sudo -u www-data -i จะไม่ทำงาน เนื่องจาก login shell ของบัญชีดังกล่าวคือ /usr/sbin/nologin และคุณจะได้รับ This account is currently not available. การส่งคำสั่งโดยตรงไปยัง sudo -u จะเป็นการข้าม login shell ทำให้สามารถทำงานได้ตามปกติ
จากนั้นตรวจสอบให้แน่ใจว่า WordPress มองเห็นค่าคงที่จากขั้นตอนที่ 1 แล้ว:
sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com eval 'var_dump( DISABLE_WP_CRON );'คำสั่งนี้จะแสดงผลเป็น bool(true) หากเกิด fatal error เกี่ยวกับค่าคงที่ที่ไม่ได้กำหนด (undefined constant) แสดงว่าบรรทัด define() ไม่ถูกประมวลผล ซึ่งโดยปกติหมายความว่าบรรทัดดังกล่าวถูกวางไว้หลังคำสั่ง require
ขั้นตอนที่ 3: เพิ่มรายการ cron ด้วยผู้ใช้ที่ถูกต้อง
ผู้ใช้ที่ถูกต้องคือผู้ใช้ที่เป็นเจ้าของไฟล์ที่ PHP เขียนข้อมูลลงไป ให้ตรวจสอบทั้งสองฝั่ง:
stat -c '%U %G' /srv/www/example.com/wp-content/uploads
grep -E '^(user|group) = ' /etc/php/8.3/fpm/pool.d/www.confในการติดตั้ง Ubuntu แบบค่าเริ่มต้น ทั้งสองค่าคือ www-data หากคุณกำหนด PHP-FPM pool แยกสำหรับเว็บไซต์โดยใช้ผู้ใช้เฉพาะ ซึ่งเป็นจุดที่การตั้งค่ารายเว็บไซต์บน LAMP stack บน Ubuntu 24.04 มักจะไปถึง ให้ใช้ผู้ใช้นั้นสำหรับทุกขั้นตอนด้านล่าง
สร้างไดเรกทอรี log ที่ผู้ใช้ดังกล่าวสามารถเขียนไฟล์ได้:
sudo install -d -o www-data -g www-data -m 750 /var/log/wp-cronแก้ไข crontab ของผู้ใช้นั้น:
sudo crontab -u www-data -eเพิ่มหนึ่งบรรทัด:
*/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-example.lock /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now >> /var/log/wp-cron/example.log 2>&1อธิบายทีละส่วน */5 สั่งให้รันทุกห้านาที flock -n ใช้ lock file และจะยกเลิกการทำงานทันทีหากการรันครั้งก่อนหน้ายังคงค้างอยู่ /usr/local/bin/wp คือพาธแบบสมบูรณ์ (absolute path) ซึ่ง cron จำเป็นต้องใช้ --path ช่วยให้คำสั่งรันได้จากทุกไดเรกทอรีทำงาน --due-now สั่งให้รันเฉพาะเหตุการณ์ที่ถึงเวลาแล้วเท่านั้น แทนที่จะรันทุกเหตุการณ์ในคิว การ redirect จะส่งผลลัพธ์ปกติและข้อผิดพลาดไปยังไฟล์เดียวที่คุณสามารถอ่านได้
ในทางปฏิบัติ การ redirect นี้ไม่ใช่ทางเลือกเสริม Cron จะส่งผลลัพธ์ของงานไปยังผู้ใช้ผ่านอีเมล แต่ VPS ส่วนใหญ่ไม่ได้ติดตั้ง mail transfer agent ไว้ ทำให้ cron บันทึก (CRON) info (No MTA installed, discarding output) และทิ้งผลลัพธ์นั้นไป การใช้ไฟล์จะช่วยเก็บหลักฐานไว้ได้
ตรวจสอบไฟล์ที่บันทึกไว้:
sudo crontab -u www-data -lสำหรับหลายเว็บไซต์ ให้ใช้บรรทัดละหนึ่งรายการโดยเหลื่อมเวลานาทีกัน เพื่อไม่ให้ทุกงานเริ่มทำงานพร้อมกัน:
*/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-one.lock /usr/local/bin/wp --path=/srv/www/one.example.com cron event run --due-now >> /var/log/wp-cron/one.log 2>&1
2-59/5 * * * * /usr/bin/flock -n /run/lock/wp-cron-two.lock /usr/local/bin/wp --path=/srv/www/two.example.com cron event run --due-now >> /var/log/wp-cron/two.log 2>&1ไฟล์ log จะขยายขนาดขึ้นเรื่อยๆ จนกว่าคุณจะทำการหมุนไฟล์ (rotate) ให้เขียนไฟล์ /etc/logrotate.d/wp-cron:
/var/log/wp-cron/*.log {
weekly
rotate 4
missingok
notifempty
compress
create 640 www-data www-data
}ตรวจสอบว่าไฟล์ถูก parse อย่างถูกต้องโดยไม่มีการแก้ไขใดๆ: sudo logrotate --debug /etc/logrotate.d/wp-cron
ขั้นตอนที่ 4: ยืนยันว่าเหตุการณ์ที่ตั้งเวลาไว้ทำงานจริง
บรรทัดใน crontab ที่บันทึกสำเร็จไม่ได้เป็นเครื่องพิสูจน์ว่างานทำงานได้จริง ให้ตรวจสอบไล่ลำดับจากวิธีที่ง่ายที่สุดไปจนถึงวิธีที่ยืนยันผลลัพธ์ได้แน่นอน
ขั้นแรก cron ได้เริ่มคำสั่งหรือไม่? cron จะบันทึก log ลงใน journal ภายใต้ unit ของตัวเอง:
journalctl -u cron.service --since "15 min ago" | grep wpรายการที่ปกติจะมีลักษณะดังนี้ (ตัด timestamp และชื่อโฮสต์ออก):
CRON[24913]: (www-data) CMD (/usr/bin/flock -n /run/lock/wp-cron-example.lock /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now >> /var/log/wp-cron/example.log 2>&1)บรรทัดนั้นหมายความว่า cron ได้เริ่มคำสั่งของคุณในฐานะ www-data แล้ว แต่มันไม่ได้ระบุว่าคำสั่งนั้นทำงานสำเร็จหรือไม่
ขั้นที่สอง WordPress ได้ดำเนินการใดๆ หรือไม่? ให้ตรวจสอบไฟล์ log:
sudo tail -n 20 /var/log/wp-cron/example.logWP-CLI จะพิมพ์หนึ่งบรรทัดต่อหนึ่งเหตุการณ์ และสรุปผลรวมในตอนท้าย:
Executed the cron event 'wp_version_check' in 0.418s.
Success: Executed a total of 2 cron events.ข้อผิดพลาดจะถูกบันทึกไว้ในไฟล์เดียวกัน ซึ่งเป็นจุดประสงค์หลักของ 2>&1 ในการทำงานส่วนใหญ่ที่ไม่มีงานค้าง ไฟล์จะไม่มีข้อมูลบันทึกมากนัก ดังนั้นควรตรวจสอบไฟล์หลังจากช่วงเวลาที่คุณทราบว่ามีงานที่ต้องทำ
ขั้นที่สาม ตรวจสอบแบบ end-to-end ให้ตั้งเวลาเหตุการณ์ทดสอบแล้วเฝ้าดูว่ามันหายไปหรือไม่:
sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event schedule wp_cli_cron_check now
sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event list --fields=hook,next_run_relative --format=csv | grep wp_cli_cron_checkรอให้ครบหนึ่งช่วงเวลา แล้วรันคำสั่งแสดงรายการอีกครั้ง หาก hook หายไป แสดงว่าทำงานแล้ว เพราะเหตุการณ์แบบครั้งเดียวจะถูกลบออกจากคิวเมื่อทำงานเสร็จสิ้น เนื่องจากไม่มีปลั๊กอินใดลงทะเบียน callback ไว้กับชื่อ hook นั้น การรันจึงไม่มีผลกระทบอื่นต่อเว็บไซต์ หาก hook ยังคงอยู่ในรายการหลังจากผ่านไปสองช่วงเวลา แสดงว่าคิวไม่ได้ถูกประมวลผล และการตรวจสอบสองขั้นตอนแรกจะบอกคุณได้ว่าปัญหาอยู่ที่ cron หรือ WP-CLI
ห้ามใช้ wp cron test สำหรับการตรวจสอบนี้ คำสั่งดังกล่าวใช้ตรวจสอบว่าการเรียกใช้งานผ่านผู้เข้าชม (visitor triggered spawning) ทำงานหรือไม่ และจะแสดงข้อผิดพลาดเมื่อ DISABLE_WP_CRON เป็น true บนเซิร์ฟเวอร์ที่ตั้งค่าไว้อย่างถูกต้อง ข้อผิดพลาดนั้นคือผลลัพธ์ที่คาดหวัง ไม่ใช่ความผิดปกติของระบบ
ทางเลือกด้วย systemd timer
หากงานตามกำหนดการอื่นๆ ของเซิร์ฟเวอร์ทำงานผ่าน systemd services and timers อยู่แล้ว ให้ย้าย WordPress ไปไว้ที่นั่นด้วย การทำงานทุกครั้งจะปรากฏใน systemctl list-timers และผลลัพธ์จะถูกส่งไปยัง journal แทนการเขียนลงไฟล์ที่คุณต้องคอยจัดการหมุนเวียนไฟล์ (rotate)
สร้างไฟล์ /etc/systemd/system/wp-cron-example.service:
[Unit]
Description=Run due WordPress cron events for example.com
[Service]
Type=oneshot
User=www-data
Group=www-data
ExecStart=/usr/local/bin/wp --path=/srv/www/example.com cron event run --due-nowจากนั้นสร้าง /etc/systemd/system/wp-cron-example.timer:
[Unit]
Description=Run WordPress cron for example.com every 5 minutes
[Timer]
OnCalendar=*:0/5
AccuracySec=30s
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now wp-cron-example.timer
systemctl list-timers wp-cron-example.timer
journalctl -u wp-cron-example.service -n 20Systemd จะไม่รัน service เดียวกันซ้อนกันสองตัวพร้อมกัน ดังนั้นเวอร์ชันนี้จึงไม่จำเป็นต้องใช้ flock ส่วน Persistent=true จะช่วยให้งานที่พลาดไปในช่วงที่เครื่องปิดอยู่กลับมาทำงานต่อได้ ซึ่งเป็นสิ่งที่ crontab ทำไม่ได้
ให้เลือกใช้ระหว่าง crontab หรือ timer อย่างใดอย่างหนึ่ง การรันทั้งสองอย่างกับเว็บไซต์เดียวกันจะทำให้คิวถูกประมวลผลสองครั้ง และลูกค้าของคุณอาจเห็นงานประเภทอีเมลหรือคำสั่งซื้อถูกประมวลผลซ้ำได้
เหตุผลที่ cron job ไม่ควรทำงานในฐานะ root
นี่เป็นวิธีแรกจาก 3 วิธีที่ทำให้การตั้งค่าล้มเหลว หากคุณใส่ job ไว้ใน crontab ของ root ตัว WP-CLI จะหยุดทำงานก่อนที่จะเริ่มดำเนินการใดๆ:
Error: YIKES! It looks like you're running this as root.คิวจะไม่ถูกประมวลผล และหากคุณไม่ได้เปลี่ยนเส้นทาง output (redirect output) คุณจะไม่เห็นข้อความแจ้งเตือนใดๆ วิธีแก้ไขที่อันตรายคือการเพิ่ม --allow-root เพราะจะทำให้ทุกไฟล์ที่ปลั๊กอินเขียนขึ้นระหว่างการทำงานนั้นมีเจ้าของเป็น root เมื่อมีการร้องขอผ่านเว็บในครั้งถัดไปซึ่งทำงานในฐานะ www-data ระบบจะไม่สามารถเขียนไฟล์ลงในไดเรกทอรีเหล่านั้นได้ และเว็บไซต์จะเริ่มแสดงข้อผิดพลาดดังนี้:
Unable to create directory wp-content/uploads/2026/08. Is its parent directory writable by the server?ให้แก้ไขความเป็นเจ้าของไฟล์ (ownership) ให้ถูกต้อง จากนั้นจึงย้าย job ไปไว้ในที่ที่เหมาะสม:
sudo chown -R www-data:www-data /srv/www/example.com/wp-contentcrontab ของ root และ crontab ของ www-data เป็นไฟล์แยกจากกัน ดังนั้นการลบบรรทัดออกจากที่หนึ่งจะไม่ส่งผลกระทบต่ออีกที่หนึ่ง ให้ตรวจสอบทั้งสองตำแหน่ง:
sudo crontab -u root -l
sudo crontab -u www-data -lเหตุใด cron จึงรายงาน wp: not found
นี่เป็นความล้มเหลวครั้งที่สอง cron กำหนดค่า PATH ที่สั้นมากให้กับงานของผู้ใช้ คือ /usr/bin:/bin ในขณะที่ WP-CLI ติดตั้งอยู่ใน /usr/local/bin ซึ่งไม่อยู่ในรายการดังกล่าว งานจึงเริ่มทำงานแล้วล้มเหลวภายในเสี้ยววินาที โดยมีบันทึกเพียงบรรทัดเดียวใน log:
/bin/sh: 1: wp: not foundให้ตรวจสอบสภาพแวดล้อมของ cron ด้วยตนเองแทนการคาดเดา โดยเพิ่มบรรทัดชั่วคราวเข้าไปดังนี้:
*/5 * * * * env > /tmp/cron-env.txt 2>&1อ่านไฟล์ /tmp/cron-env.txt หลังจากผ่านไปหนึ่งรอบการทำงาน แล้วจึงลบคำสั่งนั้นออก ค่า PATH= ในไฟล์ดังกล่าวคือสิ่งที่งานของคุณได้รับจริง
การแก้ไขทำได้สองวิธี วิธีแรกคือใช้พาธแบบสมบูรณ์ /usr/local/bin/wp ตามขั้นตอนที่ 3 หรือวิธีที่สองคือการกำหนดค่า PATH ไว้ที่ด้านบนสุดของ crontab เหนือบรรทัดงานทั้งหมด:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binกับดักเดียวกันนี้ยังเกิดขึ้นในระดับถัดไป ไฟล์ wp phar เริ่มต้นด้วย #!/usr/bin/env php ดังนั้น shell จึงต้องหา php ให้พบด้วย หาก PHP ติดตั้งอยู่นอก /usr/bin ซึ่งมักเกิดขึ้นกับ custom build หรือ build จาก control panel คุณจะพบข้อผิดพลาด:
/usr/bin/env: 'php': No such file or directoryในกรณีนี้ ให้เรียกใช้ interpreter โดยระบุพาธให้ชัดเจน เช่น /usr/local/bin/php /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-now
เหตุใดช่วงเวลาหนึ่งนาทีจึงทำให้เกิดปัญหาเดิมซ้ำ
นี่เป็นความล้มเหลวครั้งที่สาม * * * * * ให้ความรู้สึกปลอดภัยกว่าห้านาที แต่สำหรับเว็บไซต์ที่มีการใช้งานสูง มันจะทำให้คุณกลับไปสู่จุดเริ่มต้น หากการทำงานหนึ่งรอบใช้เวลานานกว่าช่วงเวลาที่กำหนด รอบถัดไปจะเริ่มขึ้นในขณะที่รอบแรกยังไม่เสร็จสิ้น สิบนาทีผ่านไปจะมีกระบวนการ PHP จำนวนสิบรายการ แต่ละรายการใช้หน่วยความจำและการเชื่อมต่อฐานข้อมูลของตนเอง
ตรวจสอบการสะสมของกระบวนการโดยตรง:
ps -eo etimes,user,args | grep '[c]ron event run'etimes คืออายุของกระบวนการในหน่วยวินาที หากมีเพียงหนึ่งบรรทัดแสดงว่าสถานะปกติ แต่หากมีหลายบรรทัดที่มีอายุมากกว่าช่วงเวลาที่คุณกำหนดไว้อย่างมาก แสดงว่ามีการทำงานซ้อนทับกัน ซึ่งบน VPS ขนาดเล็กจะจบลงด้วยข้อผิดพลาด Too many connections ของ MySQL หรือการที่ kernel สั่งยุติการทำงานของ PHP เพื่อคืนหน่วยความจำ ซึ่งคุณสามารถตรวจสอบได้ด้วย sudo dmesg -T | grep -i 'killed process'
WP-CLI เรียกใช้ event callback โดยตรงแทนการร้องขอผ่าน wp-cron.php ดังนั้นการล็อก 60 วินาทีที่ WordPress ใช้เพื่อป้องกันการเรียกซ้ำจึงไม่มีผลในกรณีนี้ flock -n ในขั้นตอนที่ 3 คือสิ่งที่ป้องกันการซ้อนทับในปัจจุบัน การทำงานที่ถูกข้ามไปจะยุติลงทันทีโดยไม่มีการแจ้งเตือน ซึ่งเป็นไปตามการออกแบบ
ให้เลือกช่วงเวลาจากกำหนดการที่สั้นที่สุดที่คุณจำเป็นต้องใช้จริง และวัดระยะเวลาการทำงานก่อน:
time sudo -u www-data /usr/local/bin/wp --path=/srv/www/example.com cron event run --due-nowห้านาทีเป็นค่าเริ่มต้นที่เหมาะสม: โพสต์ที่กำหนดเวลาไว้ 09:00 จะถูกเผยแพร่ภายใน 09:05 ส่วนสิบห้านาทีนั้นเพียงพอสำหรับเว็บไซต์ที่ไม่มีเนื้อหาสำคัญเรื่องเวลา สำหรับช่วงเวลาหนึ่งนาทีนั้นเหมาะสำหรับร้านค้าและปลั๊กอินที่ทำงานผ่านคิวซึ่งจำเป็นต้องใช้จริงๆ และควรใช้ก็ต่อเมื่อคุณทราบแล้วว่าการทำงานหนึ่งรอบใช้เวลาเพียงไม่กี่วินาทีเท่านั้น
หากคุณไม่สามารถติดตั้ง WP-CLI ได้
โฮสต์บางแห่งบล็อกการใช้งานเครื่องมือผ่านเชลล์ คุณสามารถส่ง HTTP request แบบปกติไปยัง wp-cron.php เพื่อรันคิวเดียวกันได้ โดยคำสั่งจะทำงานผ่านเว็บสแต็กทั้งหมด:
*/5 * * * * /usr/bin/curl -sS --max-time 120 "https://example.com/wp-cron.php?doing_wp_cron" > /dev/nullสิ่งที่คุณจะสูญเสียไปอย่างชัดเจนมีดังนี้:
- การทำงานจะถูกจำกัดด้วยค่า timeout ของเว็บเซิร์ฟเวอร์และ PHP-FPM ดังนั้นงานที่ใช้เวลานานอาจถูกตัดจบกลางคัน
- ใบรับรองต้องถูกต้อง มิฉะนั้น
curlจะหยุดทำงานพร้อมกับแจ้งข้อผิดพลาดSSL certificate problemดังนั้นต้องดูแลให้การต่ออายุใบรับรองทำงานได้ตามปกติด้วย Certbot บน nginx - ระบบแคชหน้าเว็บต้องไม่แคช
wp-cron.phpมิฉะนั้นคำขอจาก cron จะได้รับผลลัพธ์ที่ถูกแคชไว้และไม่มีงานใดถูกประมวลผล - คุณจะไม่ได้รับเอาต์พุตแบบเรียลไทม์ระหว่างการทำงาน ดังนั้นหลักฐานเดียวที่ยืนยันว่างานได้รันแล้วคือผลลัพธ์ที่เกิดขึ้นจริง
-sS ช่วยให้ curl ไม่แสดงผลลัพธ์เมื่อทำงานสำเร็จ แต่ยังคงแสดงข้อผิดพลาดหากเกิดขึ้น ซึ่งเป็นสิ่งที่คุณต้องการสำหรับการตั้งค่า cron job
สิ่งที่ควรอยู่ในตารางเวลาของเซิร์ฟเวอร์
เมื่อ system cron ดูแลคิวของ WordPress แล้ว ให้เก็บงานประจำอื่นๆ ของเซิร์ฟเวอร์ไว้ในที่เดียวกันเพื่อให้ตรวจสอบได้ง่าย การติดตั้งแพตช์ความปลอดภัยของระบบปฏิบัติการควรใช้ unattended upgrades แทนการเขียน cron line ที่ต้องดูแลด้วยตนเอง ส่วนการอัปเดตปลั๊กอินและธีมของ WordPress เป็นการตัดสินใจที่ต่างออกไป เพราะ wp plugin update --all ใน crontab อาจทำให้เว็บไซต์ที่ใช้งานจริงล่มได้ในเวลาตี 3 โดยไม่มีใครเฝ้าระวัง ดังนั้นควรดำเนินการด้วยความตั้งใจ หรือทำผ่านขั้นตอน staging และมีการสำรองข้อมูลก่อนเสมอ
FAQ
การปิดใช้งาน WP-Cron จะทำให้โพสต์ที่ตั้งเวลาไว้ไม่เผยแพร่หรือไม่?
ไม่ หากมีกระบวนการอื่นคอยรันคิวงานอยู่ DISABLE_WP_CRON เพียงแค่หยุดไม่ให้การโหลดหน้าเว็บเป็นตัวกระตุ้นคิวงานเท่านั้น เหตุการณ์ต่างๆ ยังคงถูกกำหนดเวลาไว้เหมือนเดิมทุกประการ โพสต์ที่ตั้งเวลาไว้ 09:00 จะถูกเผยแพร่ในการรัน cron ครั้งแรกหลังจาก 09:00 ดังนั้นหากตั้งช่วงเวลาไว้ 5 นาที โพสต์จะถูกเผยแพร่ภายใน 09:05 หากคุณกำหนดค่า constant นี้ไว้แต่ไม่ได้เพิ่มรายการ cron เข้าไป โพสต์จะค้างอยู่ในรายการโดยมีสถานะเป็น Missed schedule จนกว่าจะมีกระบวนการอื่นมารันคิวงานนั้น
ควรใช้ผู้ใช้ใดในการรัน WordPress cron job?
ควรใช้ผู้ใช้ที่เป็นเจ้าของไฟล์ที่ PHP เขียน ซึ่งโดยปกติคือ www-data บนการติดตั้ง Ubuntu มาตรฐาน ให้ตรวจสอบด้วยคำสั่ง stat -c '%U %G' /srv/www/example.com/wp-content/uploads และเปรียบเทียบกับบรรทัด user = ในไฟล์กำหนดค่า PHP-FPM pool ของคุณ การรันงานในฐานะ root จะทำให้ WP-CLI หยุดทำงานพร้อมข้อความแสดงข้อผิดพลาด YIKES และการบังคับรันด้วย --allow-root จะทำให้ไฟล์ภายใน wp-content มี root เป็นเจ้าของ ซึ่งเว็บเซิร์ฟเวอร์จะไม่สามารถเขียนทับได้ในภายหลัง
ควรตั้งค่า system cron ให้รัน WordPress cron บ่อยแค่ไหน?
ทุกๆ 5 นาทีเหมาะสมสำหรับเว็บไซต์ส่วนใหญ่ ให้ปรับช่วงเวลาให้ตรงกับตารางเวลาที่สั้นที่สุดที่คุณใช้งานจริง และรักษาช่วงเวลาให้มากกว่าระยะเวลาที่ใช้ในการรันหนึ่งรอบอย่างเพียงพอ ซึ่งคุณสามารถวัดได้โดยการใส่ time ไว้หน้าคำสั่ง WP-CLI การตั้งช่วงเวลา 1 นาทีอาจทำให้การรันงานซ้อนทับกันบนเว็บไซต์ที่มีการใช้งานสูง เว้นแต่จะมี flock คอยป้องกันไว้
ทำไม wp cron test ถึงล้มเหลวหลังจากที่ฉันปิดใช้งาน WP-Cron?
เพราะคำสั่งนั้นเป็นการทดสอบการสร้างกระบวนการโดยผู้เข้าชม และมันจะรายงานข้อผิดพลาดเมื่อ DISABLE_WP_CRON ถูกตั้งค่าเป็น true ซึ่งถือเป็นผลลัพธ์ที่ถูกต้องบนเซิร์ฟเวอร์ที่กำหนดค่าในลักษณะนี้ ให้ตรวจสอบผ่าน system cron แทน: อ่านจาก /var/log/wp-cron/example.log หรือกำหนดเหตุการณ์ตัวบ่งชี้ด้วย wp cron event schedule แล้วตรวจสอบว่ามันหายไปจาก wp cron event list หลังจากรันครั้งถัดไปหรือไม่
ฉันจำเป็นต้องใช้ WP-CLI หรือการใช้ curl เรียก wp-cron.php ก็เพียงพอแล้ว?
curl สามารถใช้งานได้ และเป็นคำตอบที่เหมาะสมเมื่อคุณไม่สามารถติดตั้ง WP-CLI ได้ แต่มันจะทำงานช้ากว่าเพราะต้องโหลด WordPress ผ่านเว็บเซิร์ฟเวอร์และถูกจำกัดด้วย request timeout ในขณะที่ WP-CLI จะรันเหตุการณ์ต่างๆ ในกระบวนการ PHP แบบ command line ซึ่งไม่มีการจำกัดเวลาของเว็บ และจะแสดงผลลัพธ์หนึ่งบรรทัดต่อหนึ่งเหตุการณ์พร้อมระยะเวลาที่ใช้ ทำให้ log บอกคุณได้อย่างแม่นยำว่ามีอะไรทำงานบ้างและใช้เวลานานเท่าใด