วัน: 20 เมษายน 2017

MacOd: caffeinate ใช้แล้วก็ยังหลับใน แก้โดยMacOd: caffeinate ใช้แล้วก็ยังหลับใน แก้โดย

สาเหตุหลักที่รันด้วย caffeinate -dimsu บน macOS แล้วสคริปต์ยังหยุดทำงานหรือทำงานไม่ต่อเนื่องเมื่อทิ้งเครื่องไว้ เกิดจาก พฤติกรรมการจัดการพลังงานระดับ OS (App Nap / Sleep Mode) ผสมกับคอขวดของ HTTP Requests และ Ollama โดยมีจุดที่ต้องตรวจสอบและแก้ไขดังนี้ครับ


สาเหตุหลักที่ทำให้เหมือนหยุดทำงาน

  1. พับฝาจอ MacBook (Clamshell Sleep)
    • แม้จะใส่ caffeinate -dimsu แต่ถ้าเป็น MacBook แล้วไม่ได้เสียบสายชาร์จ (Power Adapter) ไว้ หรือไม่ได้ต่อจอนอก เมื่อพับฝาลง ระบบจะบังคับ System Sleep ทันที คำสั่ง caffeinate ทั่วไปจะไม่สามารถฝืนฮาร์ดแวร์ sleep ตอนพับฝาได้
  2. macOS App Nap บังคับจำกัดการทำงานของ Terminal
    • เมื่อหน้าต่าง Terminal หรือแอปที่รันอยู่ไม่ได้อยู่โฟกัสด้านหน้า (Backgrounded) หรือหน้าจอดับลง macOS จะเข้าสู่โหมดประหยัดพลังงาน บีบ Thread Priority และลด I/O ของโปรเซสนั้นลง ทำให้ตัวรันแทบหยุดนิ่ง
  3. Wi-Fi / Network Drop ตอนหน้าจอดับ
    • บน Apple Silicon macOS มักจะตัดหรือลดแบนด์วิดท์ Wi-Fi เมื่อไม่ได้ใช้งาน ทำให้ Request ที่ส่งไปยัง WordPress REST API หรือดึง Reference ค้างไปจน Timeout
  4. Ollama ค้างหรือหมด Timeout (600 วินาที)
    • ในโค้ดมีการตั้ง timeout=600 (10 นาที) ต่อ 1 call ของ Ollama หาก Model รันโมเดลขนาดใหญ่ (gemma4:latest) แล้ว CPU/GPU โดน Throttle จากความร้อนหรือประหยัดพลังงาน ตัวสคริปต์จะค้างนิ่งเพื่อรอ Response นานเป็นสิบนาที จนดูเหมือนโปรแกรมไม่ทำงาน

วิธีแก้ไขการตั้งค่าบน macOS

ก. กรณีใช้งานบน MacBook

  • เสียบสายชาร์จไว้เสมอ ขณะรันงาน Batch Process ระยะยาว
  • อย่าพับฝาจอลง (ยกเว้นต่อจอนอก, เมาส์, คีย์บอร์ด และเสียบไฟ เพื่อเข้า Clamshell mode เต็มรูปแบบ)

ข. ปิด App Nap ให้กับ Terminal / iTerm2

รันคำสั่งใน Terminal เพื่อไม่ให้ระบบลด Priority ของ Terminal ตอนทิ้งเครื่องไว้

Bash

BASH / Shell

# สำหรับ Terminal ค่าเริ่มต้นของ macOS
defaults write com.apple.Terminal NSAppSleepDisabled -bool YES

# หรือถ้าใช้ iTerm2
defaults write com.googlecode.iterm2 NSAppSleepDisabled -bool YES

ค. สั่งรันด้วย caffeinate แบบระบุโปรเซสให้ผูกติดโดยตรง

คำสั่งเดิมที่ใช้ดีอยู่แล้ว แต่แนะนำให้เพิ่ม flag ป้องกันการ sleep ของฮาร์ดแวร์ขณะเสียบชาร์จ:

Bash

BASH / Shell

caffeinate -dis -w $$ &
python3 wp_loop_post_update.py --start-id 3512 --mode verify

หรือรันแบบเดิมโดยมั่นใจว่าเสียบสายชาร์จและเปิดฝาจอไว้

Bash

BASH / Shell

caffeinate -dimsu python3 wp_loop_post_update.py --start-id 3512 --mode verify

3. จุดที่ควรปรับปรุงในโค้ด Python เพื่อไม่ให้ค้าง

ในสคริปต์มีจุดที่ Request อาจค้างเงียบ ๆ นานเกินไป ทำให้ดูเหมือนโปรเซสหยุดเดิน

1) เพิ่ม Keep-Alive และ Retry Strategy ให้กับ SESSION

ป้องกันอาการ Connection หลุดเงียบ ๆ จากระบบ Network

Python

BASH / Shell

from urllib3.util import Retry
from requests.adapters import HTTPAdapter

retries = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retries, pool_connections=10, pool_maxsize=10)
SESSION.mount("http://", adapter)
SESSION.mount("https://", adapter)

2) ลด Timeout ของ Ollama และใส่ Log แสดงความคืบหน้าระหว่างรอ

ในฟังก์ชัน generate_article_content_with_llm มี timeout=600 ถ้า LLM เจนช้า คุณจะไม่เห็นเอาต์พุตเลยตลอด 10 นาที แนะนำให้ลดลงเหลือประมาณ 180 หรือ 240 วินาที และพิมพ์ Log บอกก่อนยิง API:

Python

BASH / Shell

print(f"      ⏳ กำลังส่ง Prompt ให้ Ollama ({model_name})...")
res = SESSION.post(OLLAMA_URL, json=payload, timeout=240)

3) เปิด Unbuffered Mode ใน Python

เวลาทิ้งรันไว้นาน ๆ บางครั้งเอาต์พุตจะไม่ยอม Flush ออกมาที่หน้าจอ Terminal จนกว่าบัฟเฟอร์จะเต็ม ทำให้มองไม่เห็น Log ล่าสุด

รันด้วย flag -u:

Bash

BASH / Shell

caffeinate -dimsu python3 -u wp_loop_post_update.py --start-id 3512 --mode verify